MutableCollection 与 RangeReplaceableCollection
MutableCollection vs RangeReplaceableCollection
来自Apple's MutableCollection
API reference:
The MutableCollection
protocol allows changing the values of a collection’s elements but not the length of the collection itself. For operations that require adding or removing elements, see the RangeReplaceableCollection
protocol instead.
但是,MutableCollection
需要以下下标:
subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get set }
这不允许更改集合的长度吗?例如,我们不能用一个空范围和一个非空子序列来调用这个下标的 setter 吗?
简答:
如果你有MutableCollection
的变量
type 那么你必须调用下标 setter 只有一个范围
和一个具有相同长度的新切片。
一些符合MutableCollection
的类型(比如Array
)允许一个different-length替换来插入或删除元素,
但一般来说,可变的 collection 不需要这样。
特别是 默认实现 MutableCollection
下标 setter 如果范围和
新切片的长度不同。
更长的答案:
首先请注意,您不必实施
public subscript(bounds: Range<Index>) -> MutableSlice<Self>
在你自己的 collection 因为它在
协议扩展。正如在该方法的 source code 中看到的那样,下标 setter 调用 a
internal func _writeBackMutableSlice()
实现的功能here。
该函数首先从
切片到目标范围,然后验证下标范围和新切片的长度是否相同:
_precondition(
selfElementIndex == selfElementsEndIndex,
"Cannot replace a slice of a MutableCollection with a slice of a smaller size")
_precondition(
newElementIndex == newElementsEndIndex,
"Cannot replace a slice of a MutableCollection with a slice of a larger size")
所以你不能通过改变 MutableCollection
的长度
(默认)下标 setter,尝试这样做会中止程序。
例如,让我们定义一个 "minimal" 类型符合
MutableCollection
:
struct MyCollection : MutableCollection, CustomStringConvertible {
var storage: [Int] = []
init(_ elements: [Int]) {
self.storage = elements
}
var description: String {
return storage.description
}
var startIndex : Int { return 0 }
var endIndex : Int { return storage.count }
func index(after i: Int) -> Int { return i + 1 }
subscript(position : Int) -> Int {
get {
return storage[position]
}
set(newElement) {
storage[position] = newElement
}
}
}
然后用相同长度的切片替换collection的一部分
作品:
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc[1 ... 2] = mc[3 ... 4]
print(mc) // [0, 3, 4, 3, 4, 5]
但对于不同的长度,它会因运行时异常而中止:
mc[1 ... 2] = mc[3 ... 3]
// fatal error: Cannot replace a slice of a MutableCollection with a slice of a smaller size
注意具体类型符合MutableCollection
可能
允许 different-lengths 替换他们的下标 setter,
例如 Array
就是这样。
来自Apple's MutableCollection
API reference:
The
MutableCollection
protocol allows changing the values of a collection’s elements but not the length of the collection itself. For operations that require adding or removing elements, see theRangeReplaceableCollection
protocol instead.
但是,MutableCollection
需要以下下标:
subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get set }
这不允许更改集合的长度吗?例如,我们不能用一个空范围和一个非空子序列来调用这个下标的 setter 吗?
简答:
如果你有MutableCollection
的变量
type 那么你必须调用下标 setter 只有一个范围
和一个具有相同长度的新切片。
一些符合MutableCollection
的类型(比如Array
)允许一个different-length替换来插入或删除元素,
但一般来说,可变的 collection 不需要这样。
特别是 默认实现 MutableCollection
下标 setter 如果范围和
新切片的长度不同。
更长的答案:
首先请注意,您不必实施
public subscript(bounds: Range<Index>) -> MutableSlice<Self>
在你自己的 collection 因为它在 协议扩展。正如在该方法的 source code 中看到的那样,下标 setter 调用 a
internal func _writeBackMutableSlice()
实现的功能here。 该函数首先从 切片到目标范围,然后验证下标范围和新切片的长度是否相同:
_precondition(
selfElementIndex == selfElementsEndIndex,
"Cannot replace a slice of a MutableCollection with a slice of a smaller size")
_precondition(
newElementIndex == newElementsEndIndex,
"Cannot replace a slice of a MutableCollection with a slice of a larger size")
所以你不能通过改变 MutableCollection
的长度
(默认)下标 setter,尝试这样做会中止程序。
例如,让我们定义一个 "minimal" 类型符合
MutableCollection
:
struct MyCollection : MutableCollection, CustomStringConvertible {
var storage: [Int] = []
init(_ elements: [Int]) {
self.storage = elements
}
var description: String {
return storage.description
}
var startIndex : Int { return 0 }
var endIndex : Int { return storage.count }
func index(after i: Int) -> Int { return i + 1 }
subscript(position : Int) -> Int {
get {
return storage[position]
}
set(newElement) {
storage[position] = newElement
}
}
}
然后用相同长度的切片替换collection的一部分 作品:
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc[1 ... 2] = mc[3 ... 4]
print(mc) // [0, 3, 4, 3, 4, 5]
但对于不同的长度,它会因运行时异常而中止:
mc[1 ... 2] = mc[3 ... 3]
// fatal error: Cannot replace a slice of a MutableCollection with a slice of a smaller size
注意具体类型符合MutableCollection
可能
允许 different-lengths 替换他们的下标 setter,
例如 Array
就是这样。