如果我在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。

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

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

当前回答

说实话,我也遇到过这个问题。从性能的角度来看,Swift数组应该能够抛出。 让x = try a[y] 这很好,也可以理解。

其他回答

Swift 5使用

extension WKNavigationType {
    var name : String {
        get {
            let names = ["linkAct","formSubm","backForw","reload","formRelo"]
            return names.indices.contains(self.rawValue) ? names[self.rawValue] : "other"
        }
    }
}

最后却真的想做一般的喜欢

[<collection>][<index>] ?? <default>

但由于这个系列是有背景的,我想它是合适的。

快5.倍

RandomAccessCollection的扩展意味着它也可以用于ArraySlice的单个实现。我们使用startIndex和endIndex作为数组切片使用底层父数组的索引。

public extension RandomAccessCollection {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    /// - complexity: O(1)
    subscript (safe index: Index) -> Element? {
        guard index >= startIndex, index < endIndex else {
            return nil
        }
        return self[index]
    }
    
}

当你只需要从一个数组中获取值,并且你不介意一个小的性能损失(即如果你的集合不是很大),有一个基于dictionary的替代方案,它不涉及(对我来说太通用了)集合扩展:

// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;

2022

无限索引访问和安全idx访问(如果没有这样的idex,则返回nil):

public extension Collection {
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }

    subscript (infinityIdx idx: Index) -> Element where Index == Int {
        return self[ abs(idx) % self.count ]
    }
}

但是要小心,如果数组/集合为空,它将抛出异常

使用

(0...10)[safe: 11] // nil

(0...10)[infinityIdx: 11] // 0
(0...10)[infinityIdx: 12] // 1
(0...10)[infinityIdx: 21] // 0
(0...10)[infinityIdx: 22] // 1

你可以试试

if index >= 0 && index < array.count {
    print(array[index]) 
}