一尘不染

通过可选绑定在Swift中进行安全(边界检查)数组查找?

swift

如果我在Swift中有一个数组,并尝试访问超出范围的索引,那么将出现一个令人惊讶的运行时错误:

var str = ["Apple", "Banana", "Coconut"]

str[0] // "Apple"
str[3] // EXC_BAD_INSTRUCTION

但是,我本想考虑Swift带来的所有可选链接和 安全性 ,这样做很简单:

let theIndex = 3
if let nonexistent = str[theIndex] { // Bounds check + Lookup
    print(nonexistent)
    ...do other things with nonexistent...
}

代替:

let theIndex = 3
if (theIndex < str.count) {         // Bounds check
    let nonexistent = str[theIndex] // Lookup
    print(nonexistent)   
    ...do other things with nonexistent... 
}

但这不是事实-我必须使用ol’ if语句检查并确保索引小于str.count

我尝试添加自己的subscript()实现,但是不确定如何将调用传递给原始实现,或在不使用下标符号的情况下访问项目(基于索引):

extension Array {
    subscript(var index: Int) -> AnyObject? {
        if index >= self.count {
            NSLog("Womp!")
            return nil
        }
        return ... // What?
    }
}

阅读 247

收藏
2020-07-07

共1个答案

一尘不染

Alex的回答为该问题提供了很好的建议和解决方案,但是,我偶然发现了一种更好的实现此功能的方法:

Swift 3.2及更高版本

extension Collection {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Swift 3.0和3.1

extension Collection where Indices.Iterator.Element == Index {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

感谢Hamish提出了Swift 3解决方案。

迅捷2

extension CollectionType {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

let array = [1, 2, 3]

for index in -20...20 {
    if let item = array[safe: index] {
        print(item)
    }
}
2020-07-07