在 Swift 中为 Collection 下标中的 Index 创建变异集

Alb*_*tUI 3 collections subscript swift

我正在尝试修改此扩展以获得可变性:

extension Collection where Element: Equatable {
    
    /// Returns the element at the specified index iff it is within count, otherwise nil.
    subscript (safe index: Index) -> Element? {
            indices.contains(index) ? self[index] : nil
    }
}
Run Code Online (Sandbox Code Playgroud)

我想实现这个工作:

var array = ["Hello", "World"]
array[safe: 5] = "Other word" // This will not be setted because index is out of bounds, but error won't be throwed.
Run Code Online (Sandbox Code Playgroud)

当我尝试修改下标扩展名时...

extension Collection where Element: Equatable {
    
    /// Returns the element at the specified index iff it is within count, otherwise nil.
    subscript (safe index: Index) -> Element? {
        get {
            indices.contains(index) ? self[index] : nil
        }
        mutating set {
            if indices.contains(index) {
                self[index] = newValue        <<<-- ERROR
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

...我收到此错误:Missing argument label 'safe:' in subscript

Swe*_*per 6

Collectionsubscript仅获取的。

MutableCollectionArray是遵循的协议,它声明了我们都知道和喜爱的可设置项。subscript毕竟,您的扩展要求集合是可变的,并且并非所有Collections 都是可变的,只有MutableCollections 是可变的。

extension MutableCollection {
    
    /// Returns the element at the specified index iff it is within count, otherwise nil.
    subscript (safe index: Index) -> Element? {
        get {
            indices.contains(index) ? self[index] : nil
        }
        mutating set {
            if indices.contains(index), let value = newValue {
                self[index] = value
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我还在 setter 中添加了对 case when 的检查newValue == nil(因为下标具有 type Element?,您可以分配nil给它!)。在这种情况下,下标将不会执行任何操作。Element : Equatable也不需要约束。


从技术上讲,这也可以在 s 上完成,s 是遵循的RangeReplaceableCollection另一个协议。Array但下标应该是 O(1) 时间,但replaceSubrange事实并非如此。

extension RangeReplaceableCollection {
    
    /// Returns the element at the specified index iff it is within count, otherwise nil.
    subscript (safe index: Index) -> Element? {
        get {
            indices.contains(index) ? self[index] : nil
        }
        mutating set {
            if indices.contains(index), let value = newValue {
                self.replaceSubrange(index...index), with: CollectionOfOne(value))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)