国外优秀教程精译 | Swift 可选值详解(上)

英文原文

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 可选值详解(下)

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 601评论 0 6
  • 基础部分(The Basics) 当推断浮点数的类型时,Swift 总是会选择Double而不是Float。 结合...
    gamper阅读 397评论 0 3
  • Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或...
    XLsn0w阅读 193评论 2 1
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 783评论 1 3
  • 做饭这种充满生活感的事 却因为是你变得如梦似幻 看着你在厨房忙碌的身影 有一种强吻你的冲动 你说 这次看见你没有那...
    percy0016阅读 9评论 0 0