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

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

如果我在Swift中有一个数组,并尝试访问超出范围的索引,则会出现一个不足为奇的运行时错误:

var str = ["Apple", "Banana", "Coconut"]str[0] // "Apple"str[3] // EXC_BAD_INSTRUCTION

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

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

代替:

let theIndex = 3if (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?    }}


慕婉清6462132
浏览 607回答 3
3回答

莫回无

我偶然发现了一种更好的实现此功能的方法:Swift 3.2和更新版本extension&nbsp;Collection&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;Returns&nbsp;the&nbsp;element&nbsp;at&nbsp;the&nbsp;specified&nbsp;index&nbsp;if&nbsp;it&nbsp;is&nbsp;within&nbsp;bounds,&nbsp;otherwise&nbsp;nil.&nbsp;&nbsp;&nbsp;&nbsp;subscript&nbsp;(safe&nbsp;index:&nbsp;Index)&nbsp;->&nbsp;Element?&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;indices.contains(index)&nbsp;?&nbsp;self[index]&nbsp;:&nbsp;nil &nbsp;&nbsp;&nbsp;&nbsp;}}Swift 3.0和3.1extension&nbsp;Collection&nbsp;where&nbsp;Indices.Iterator.Element&nbsp;==&nbsp;Index&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;Returns&nbsp;the&nbsp;element&nbsp;at&nbsp;the&nbsp;specified&nbsp;index&nbsp;if&nbsp;it&nbsp;is&nbsp;within&nbsp;bounds,&nbsp;otherwise&nbsp;nil.&nbsp;&nbsp;&nbsp;&nbsp;subscript&nbsp;(safe&nbsp;index:&nbsp;Index)&nbsp;->&nbsp;Generator.Element?&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;indices.contains(index)&nbsp;?&nbsp;self[index]&nbsp;:&nbsp;nil &nbsp;&nbsp;&nbsp;&nbsp;}}斯威夫特2extension&nbsp;CollectionType&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;Returns&nbsp;the&nbsp;element&nbsp;at&nbsp;the&nbsp;specified&nbsp;index&nbsp;if&nbsp;it&nbsp;is&nbsp;within&nbsp;bounds,&nbsp;otherwise&nbsp;nil.&nbsp;&nbsp;&nbsp;&nbsp;subscript&nbsp;(safe&nbsp;index:&nbsp;Index)&nbsp;->&nbsp;Generator.Element?&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;indices.contains(index)&nbsp;?&nbsp;self[index]&nbsp;:&nbsp;nil &nbsp;&nbsp;&nbsp;&nbsp;}}例let&nbsp;array&nbsp;=&nbsp;[1,&nbsp;2,&nbsp;3]for&nbsp;index&nbsp;in&nbsp;-20...20&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;let&nbsp;item&nbsp;=&nbsp;array[safe:&nbsp;index]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(item) &nbsp;&nbsp;&nbsp;&nbsp;}}

慕少森

如果你真的想要这种行为,它就像你想要一个Dictionary而不是一个数组。字典nil在访问丢失的密钥时返回,这是有道理的,因为要知道密钥是否存在于字典中要困难得多,因为这些密钥可以是任何东西,在数组中密钥必须在以下范围内:0to&nbsp;count。迭代这个范围是非常常见的,你可以绝对肯定在循环的每次迭代中都有一个真正的值。我认为它不能以这种方式工作的原因是Swift开发人员做出的设计选择。举个例子:var&nbsp;fruits:&nbsp;[String]&nbsp;=&nbsp;["Apple",&nbsp;"Banana",&nbsp;"Coconut"]var&nbsp;str:&nbsp;String&nbsp;=&nbsp;"I&nbsp;ate&nbsp;a&nbsp;\(&nbsp;fruits[0]&nbsp;)"如果您已经知道索引存在,就像在大多数使用数组的情况下一样,这段代码很棒。但是,如果访问标可能可能返回nil,那么你已经改变了返回类型的Array的subscript方法是可选的。这会将您的代码更改为:var&nbsp;fruits:&nbsp;[String]&nbsp;=&nbsp;["Apple",&nbsp;"Banana",&nbsp;"Coconut"]var&nbsp;str:&nbsp;String&nbsp;=&nbsp;"I&nbsp;ate&nbsp;a&nbsp;\(&nbsp;fruits[0]!&nbsp;)"//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^&nbsp;Added这意味着每次迭代数组时都需要解包一个可选项,或者使用已知索引执行任何其他操作,因为很少有人可以访问超出范围的索引。Swift设计者在访问越界索引时以牺牲运行时异常为代价,选择了较少的可选解包。崩溃比nil你在某个地方没想到的逻辑错误更可取。我同意他们的观点。因此,您将不会更改默认Array实现,因为您将破坏所有需要来自数组的非可选值的代码。相反,您可以子类化Array,并覆盖subscript以返回可选项。或者,更实际地,您可以Array使用执行此操作的非下标方法进行扩展。extension&nbsp;Array&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Safely&nbsp;lookup&nbsp;an&nbsp;index&nbsp;that&nbsp;might&nbsp;be&nbsp;out&nbsp;of&nbsp;bounds,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;returning&nbsp;nil&nbsp;if&nbsp;it&nbsp;does&nbsp;not&nbsp;exist&nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;get(index:&nbsp;Int)&nbsp;->&nbsp;T?&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;0&nbsp;<=&nbsp;index&nbsp;&&&nbsp;index&nbsp;<&nbsp;count&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self[index] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;nil &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}}var&nbsp;fruits:&nbsp;[String]&nbsp;=&nbsp;["Apple",&nbsp;"Banana",&nbsp;"Coconut"]if&nbsp;let&nbsp;fruit&nbsp;=&nbsp;fruits.get(1)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;print("I&nbsp;ate&nbsp;a&nbsp;\(&nbsp;fruit&nbsp;)") &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;I&nbsp;ate&nbsp;a&nbsp;Banana}if&nbsp;let&nbsp;fruit&nbsp;=&nbsp;fruits.get(3)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;print("I&nbsp;ate&nbsp;a&nbsp;\(&nbsp;fruit&nbsp;)") &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;never&nbsp;runs,&nbsp;get&nbsp;returned&nbsp;nil}Swift 3更新func get(index: Int) ->T?&nbsp;需要被替换&nbsp;func get(index: Int) ->Element?
打开App,查看更多内容
随时随地看视频慕课网APP