考虑这个假设的Swift函数:
func putFirst(_ string: String) {
var str = string
let c = str.popFirst()
print(c)
}
我希望,基于this one等先前的问题,str
是一个变量,因此是可变的。但是,str.popFirst()
会抛出编译错误,
Cannot use mutating member on immutable value: 'str' is immutable
这是一个我不知道的微妙之处吗?这是Swift 4的新行为吗?我该如何解决这个问题?
答案 0 :(得分:1)
它的a useless error message;问题是Collection
上只定义了一个extension Collection where SubSequence == Self {
/// Removes and returns the first element of the collection.
///
/// - Returns: The first element of the collection if the collection is
/// not empty; otherwise, `nil`.
///
/// - Complexity: O(1)
@_inlineable
public mutating func popFirst() -> Element? {
// TODO: swift-3-indexing-model - review the following
guard !isEmpty else { return nil }
let element = first!
self = self[index(after: startIndex)..<endIndex]
return element
}
}
方法。 Here it is:
Collection
您会注意到它受到限制,SubSequence
String
本身就是这样。对于Array
(以及Set
和popFirst()
等许多其他集合类型),情况并非如此;但对于那些类型的切片都是如此。
RangeReplaceableCollection
String
上没有popFirst()
的无约束重载(RangeReplaceableCollection
符合)。对此的推理as given by Dave Abrahams in this bug report是String
应为O(1);并且popFirst()
上的实现无法保证(实际上对于popFirst()
,它是线性时间)。
反对这一点的另一个好理由as mentioned by Leo Dabus,就是extension RangeReplaceableCollection {
/// Removes and returns the first element of the collection.
///
/// Calling this method may invalidate all saved indices of this
/// collection. Do not rely on a previously stored index value after
/// altering a collection with any operation that can change its length.
///
/// - Returns: The first element of the collection if the collection is
/// not empty; otherwise, `nil`.
///
/// - Complexity: O(n)
public mutating func attemptRemoveFirst() -> Element? {
return isEmpty ? nil : removeFirst()
}
}
不会使集合的索引无效。 RRC的实施无法保证这一点。
因此,由于语义差别很大,不期望RRC上的func putFirst(_ string: String) {
var str = string
let c = str.attemptRemoveFirst()
print(c)
}
过载是非常合理的。尽管如此,你总是可以在RRC上定义一个不同名称的便捷方法:
{{1}}
然后你会说:
{{1}}