【问题标题】:MutableCollection vs RangeReplaceableCollectionMutableCollection 与 RangeReplaceableCollection
【发布时间】:2016-06-25 22:29:27
【问题描述】:

来自Apple's MutableCollection API reference

MutableCollection 协议允许更改集合元素的值,但不能更改集合本身的长度。对于需要添加或删除元素的操作,请参阅RangeReplaceableCollection 协议。

但是,MutableCollection 需要以下下标:

subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get set }

这不允许更改集合的长度吗?例如,我们不能用一个空范围和一个非空子序列来调用这个下标的 setter 吗?

【问题讨论】:

    标签: swift swift3


    【解决方案1】:

    简答:

    如果您有 MutableCollection 的变量 键入然后您必须仅使用范围调用下标设置器 和一个具有相同长度的新切片。 某些符合MutableCollection 的类型(例如Array)允许使用不同长度的替换来插入或删除元素, 但一般来说,可变集合不需要允许这样做。

    特别是MutableCollection默认实现 如果范围和 新切片的长度不同。

    更长的答案:

    首先注意,你不必实现

    public subscript(bounds: Range<Index>) -> MutableSlice<Self>
    

    在您自己的集合中,因为它在 协议扩展。正如可以在该方法的source code 中看到的那样,下标设置器调用了一个

    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 的长度 (默认)下标设置器,尝试这样做会中止程序。

    作为一个例子,让我们定义一个符合以下条件的“最小”类型 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
            }
        }
    }
    

    然后用相同长度的切片替换集合的一部分 作品:

    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的具体类型可能 允许在其下标设置器中进行不同长度的替换, 就像Array 一样。

    【讨论】:

    • 所以如果我要自己实现subscript(bounds:)(例如,如果我想要MutableSlice&lt;Self&gt;以外的其他东西),我应该只使用assert来确保元素数量匹配吗?跨度>
    • @TimVermeulen:我不是 100% 确定,但我认为您可以接受不同数量的元素。例如,Array 也符合MutableCollection,但有自己的设置器,允许插入或删除元素。 – 但是任何采用MutableCollection 参数的函数都必须假设只有相同长度的替换是可能的。
    • 有趣。我想这只是令人困惑,因为 Swift 的类型系统不能强制给定的子序列必须具有正确数量的元素(并且因为文档也没有很好地解释它)。非常感谢!
    猜你喜欢
    • 2021-01-29
    • 2017-02-27
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 2016-03-23
    相关资源
    最近更新 更多