Swift,可选包装。"?" "!"我知道它的工作原理。但为什么它比!= nil检查更好呢?

5

我知道"!"或"?"的作用。但是与!= nil检查相比,我不太确定移动到"!?"的附加好处是什么。与iOS现状相比,移动到"!?"的额外好处是什么?我觉得这只是苹果添加的一些东西,但无法真正看到与iOS现状相比的额外好处。我错过了什么吗?


2
为什么每次使用变量时都要检查 nil,而不是将其声明为非可选项,确保它永远不会是 nil 呢? - Matthias Bauch
这是一种更方便的功能,可以编写更短、更易读的代码。这不仅适用于Swift,也适用于其他语言,如Groovy。 - Arne Burmeister
2个回答

5
? 操作符在链式调用时非常方便,例如:
a?.b?.c?.doSomething()

否则,您将不得不检查abc是否为nil,这可能导致比链接更难读的代码。
另一件事是,您可以轻松地标记参数为可选的,例如:
func someFunc(arg: Type?)

很明显,这是一种可能为nil的类型,即语言强制执行此操作。否则,您会传递可能为nil的内容,并忘记检查并遇到崩溃。


我不认为有人会对你的回答进行负评。这是一个非常好的答案。谢谢! - shle2821
@shle2821,有人已经这样做了。当你获得足够的积分时,你就可以获得分开的赞成和反对票的特权。 - James Webster

5

检查是否为nil和需要对可选项进行解包之间的区别可能导致您的代码崩溃或不崩溃。如果正确使用可选项,则可以提高安全性并使代码更易读。

假设您有一个数组,并且想要获取其中的第一个值。您可以像这样执行:

if !arr.isEmpty {
    useValue(arr[0])
}

当然,很容易忘记isEmpty的部分,如果遗漏了这一点,你的代码将会因为越界错误而崩溃。

所以,有一个更好的方法:使用数组的first方法,该方法会返回一个可选项,如果数组为空,则返回nil

if let val = arr.first {
    useValue(val)
}

通过这个表单,你不可能出错。如果你忘记解包arr.first的值,就会得到编译错误。在我的眼里,使用这种方法更容易阅读。

也许你期望你的!=nil公式能够像这样工作:

if arr.first != nil {
    // all optionals would be “implicit”
    useValue(arr.first)
}

抛开你调用.first两次有点低效以及类型兼容性的问题,本质上这会让你回到原点——你可能会忘记进行nil比较,然后就会出现问题。或者,你可以采用Objective-C的方法,即认为nil是可以发送消息的——但这也会导致各种混淆(个人不喜欢将向nil隐式发送消息视为无操作的想法),同时还会引出一个问题,即如果函数返回值类型为Int等,那该怎么办。难道所有东西都必须可空?这在Obj-C领域会带来很多麻烦。

更重要的是,一旦涉及到可选项,就可以引入各种便利,例如空合并:

// default to 0 if no first element
arr.first ?? 0
// much neater than this equivalent form:
arr.first != nil ? arr.first : 0

或可选比较:
// will only be true if arr is non-nil and zero
if arr.first == 0 {

}

更多示例请参见此答案

或许你不知道的空值合并操作:在 Objective-C 中也没什么不同。可以省略“true”参数,形成稍微不同语法的空值合并运算符。例如:id element = array[0] ?: defaultValue; - James Webster
为什么你不能在 Objective-C 中只写 id first = arr.first; if (first != nil) { ... }?这样就不会调用两次 first。当你发布软件时,你测试以确保它在开发期间不会崩溃,如果它崩溃了,你在开发期间修复它。当你到达发布阶段时,你的代码已经很自信了,没有一堆 if let var = something {...} 弄乱你的方法,让你的 Objective-C 方法变得简短。 - Zhang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接