你能解释一下原因吗:
例:
var players = ["Alice", "Bob", "Cindy", "Dan"]
let firstPlayer = players.first
print(firstPlayer) // Optional("Alice")
let firstIndex = players[0]
print(firstIndex) // Alice
Run Code Online (Sandbox Code Playgroud)
(这个问题的简短答案很棒,而且正是你所需要的.我只想更深入地了解为什么以及如何与Swift Collections进行更广泛的交互以及基础类型.如果你只是想"我应该如何使用这个东西?"阅读接受的答案并忽略所有这些."
数组遵循所有集合的规则.Collection必须实现以下下标:
subscript(position: Self.Index) -> Self.Element { get }
Run Code Online (Sandbox Code Playgroud)
因此,要成为集合,Array的下标必须接受其索引并无条件地返回Element.对于多种集合,不可能创建不存在的索引,但Array使用Int作为其索引,因此它必须处理您传递超出范围的索引的可能性.在这种情况下,不可能返回一个元素,它唯一的选择是根本无法返回.这通常采取崩溃程序的形式,因为它通常比挂起程序更有用,这是另一种选择.
(这隐藏了一点类型理论,即Swift中的每个函数在技术上都可以返回"崩溃",但我们不会在类型系统中跟踪它.可以这样做来区分可能崩溃的函数和那不可以,但斯威夫特没有.)
这应该自然地提出了当你用不存在的键下标时为什么Dictionary不会崩溃的问题.原因是词典的索引不是它的关键.它有一个很少使用的下标,它提供了对Collection的一致性(在顶层代码中很少使用,但在stdlib中很常用):
subscript(position: Dictionary<Key, Value>.Index) -> Dictionary.Element { get }
Run Code Online (Sandbox Code Playgroud)
Array也可以这样做,具有Array.Index独立于Int 的类型,并使Int下标返回Optional.在Swift 1.0中,我打开了一个雷达来要求.该团队认为,这将使得Array的常见用途变得非常困难,并且来到Swift的程序员习惯了超出范围是编程错误(崩溃)的想法.另一方面,字典对于使用不存在的键进行访问是很常见的,因此Key下标应该是Optional.使用Swift好几年让我确信他们是对的.
通常,除非从数组中获取索引(即使用index(where:)),否则不应下标数组.但是许多Cocoa模式使得下标(cellForRow(at:)最着名的)非常自然.尽管如此,在更纯粹的Swift代码中,使用任意Int进行下标通常表明存在设计问题.
相反,你应该经常使用像这样的Collection方法first,first(where:)它们返回Optionals,通常更安全,更清晰,并使用for-in循环而不是下标迭代它们.
如果你想使用下标并且不想崩溃,你可以将此扩展添加到你的代码中:
extension Collection {
subscript (safe index: Index) -> Iterator.Element? {
return indices.contains(index) ? self[index] : nil
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用它:
let array = [0, 1, 2]
let second = array[safe:1] //Optional(1)
let fourth = array[safe:3] //nil instead of crash
Run Code Online (Sandbox Code Playgroud)