英文原文
Swift 是一门非常安全的语言,这里指的是 Swift 在防止代码意外崩溃方面做了很多努力。
代码崩溃的一个常见原因是试图使用一个已损坏的或不存在的数据。举例来说,假设有一个方法:
func getHaterStatus() -> String {
return "Hate"
}
该方法没有任何参数,并且返回一个 string:“Hate”。然而有一天阳光明媚,这些心有怨恨的家伙们不感到怨恨了——会发生什么事?我们可能就不想返回任何东西了:毕竟这些人今天不怨恨了嘛。
这时,一个空字符串也许是最好用来表明“没啥事”的,有时这也是事实。但是用数字如何表现“什么都没有”—— 用 0 表示“空数字”还是 -1 ?
别急着定义你自己的表示规则,Swift 已经有了解决方案:可选值。可选值就是可能有值也可能没有值的变量。大多数人都觉得可选值很难理解,别担心——我将用各种方式来说明它,总有一种方式适合你。
当使用 -> String
时,表示“这个方法会返回一个确定的 string ”,即表示该方法不会返回空值,因此它被称为安全的,因为你总是能获得一个值,这个值类型是 string 。反之,如果方法可能返回有值或空值,需要改写为下面这样:
func getHaterStatus() -> String? {
return "Hate"
}
注意这个额外的问号 String?
代表“可选的 string ”。当前的代码无论如何都会返回 “Hate”,让我们来修改一下:如果天气晴朗,怀恨者们将展开新的生活篇章,放弃他们仇恨的生活,因此返回空值。在 Swift 中,空值有特别的关键字: nil
。
于是代码改为这样:
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
}
方法接受一个 string 参数(天气 weather )并返回一个 string (仇恨状态),但返回值可能有也可能没有——为 nil 。具体到本文例子中,就表示我们可能得到一个 string ,或者得到 nil 。
那么重点来了:Swift 希望你的代码是真正安全的,使用 nil 就不是一个好主意。它会使你的代码崩溃,混淆你的代码逻辑,或者在界面上显示错误的内容。因此,当声明一个值为可选值之时,Swift 就要确保你能安全地处理它。
试着把下面这行添加到你的 playground :
var status: String
status = getHaterStatus(weather: "rainy")
第一行创建一个 string 型变量,第二行把 getHaterStatus()
的返回值赋值给这个变量——参数表示今天下雨,这样可以保证仇恨者们正在仇恨中(返回值是"Hate”)。
这段代码无法运行,因为我们声明的 String 型变量 status 要求一个值,但getHaterStatus()
可能无法提供,因为它返回可选值。也就是说,我们表示 status 一定是个 string ,但实际上 getHaterStatus()
可能啥也不返回。Swift 根本不会让你犯这个错误,这非常有用,因为它有效地阻止了一大堆常见错误。
为了解决这个问题,我们需要把 status
声明为 String?
,或者干脆移除类型声明,让 Swift 自己推断类型。第一种方法如下:
var status: String?
status = getHaterStatus(weather: "rainy")
第二种方式:
var status = getHaterStatus(weather: "rainy")
无论选择哪个,值都可能为空值,Swift 是不会让你冒险使用的。举例来说,假设有这么一个方法:
func takeHaterAction(status: String) {
if status == "Hate" {
print("Hating")
}
}
这段代码接受一个 string ,根据 string 内容打印一条消息。这个方法接受一个 String
值,却不是 String?
——你无法传递一个可选值给它,它需要一个确切的值,导致无法把 status
变量传给它。
Swift 有两个解决办法。两个都能用,但只能二选一。第一个解决方案是解包,它在条件语句中使用特定的语法规则。解包一次性做两件事情:检查可选值是否有值,如果有值就将其放入一个非可选值中并运行对应代码块。
解包语法如下:
if let unwrappedStatus = status {
// unwrappedStatus 是非可选值
} else {
// 解包失败的处理
}
if let
在一行代码中简洁地处理了检查和解包,这种方法非常常见。应用这种方法,我们能安全地把 getHaterStatus()
解包,并仅在非可选 string 有效存在时,才调用 takeHaterAction()
。
这是完整代码:
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
}
func takeHaterAction(status: String) {
if status == "Hate" {
print("Hating")
}
}
if let haterStatus = getHaterStatus(weather: "rainy") {
takeHaterAction(status: haterStatus)
}
继续阅读
国外优秀教程精译 | Swift 可选值详解(下)