Swift文档翻译计划 -- Optionals

1,361 阅读4分钟

什么是可选

可选是 Swift 独有的特性,也叫 optionals,类似于在 OC 中方法返回 nil 或返回一个对象。在 OC 中的 nil 只适用于对象,而不适用于结构体、基本 C 类型或枚举值。对于这些类型,Objective-C 方法通常返回一个特殊的值(比如 NSNotFound )来表示没有值。Swift 的 optionals 可以指示任何类型的值是否存在,而不需要特殊的常量。如果代码中的常量或变量在某些条件下需要处理缺少值的情况,需要将其声明为可选类型。

// 包含一个 int 值 404
var serverResponseCode: Int? = 404
// 不包含任何值
serverResponseCode = nil

问号表示它包含的值是可选的,这意味着它可能包含一些 Int 值,也可能根本不包含值。不能对非可选常量和变量使用 nil。

nil 在 Swift 和 OC 之间的区别

Swift 的 nil 和 Objective-C 中的 nil 不一样。在 Objective-C 中,nil 是指向不存在对象的指针。在 Swift 中,nil 不是一个指针,它是一个特定类型值的缺失。任何类型的 optionals 都可以设置为 nil,而不仅仅是对象类型。

可选的应用

Swift 的 Int 类型有一个初始化器,它试图将字符串值转换为 Int 值。但是,并不是每个字符串都可以转换为整数。字符串 “123” 可以转换为数字值 123,但是字符串 “hello, world” 没有明显的数字值可以转换。下面的例子尝试将一个字符串转换成 Int 类型:

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

因为转换可能失败,所以它返回的 convertedNumber 是一个可选的整型,而不是一个整型。可选类型则需要使用以下方式进行解包才能正常使用。

强制解析

一旦确定可选项确实包含值,就可以通过在可选项名称的末尾添加感叹号(!)来访问其基础值。这被称为可选值的强制展开:

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

这是一种不安全的解包方式,如果使用 ! 访问不存在的可选值将触发运行时错误。在使用前,一定要确保一个可选值是一个非 nil 的。

可选绑定

if let actualNumber = Int(possibleNumber) {
    print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
    print("The string \"\(possibleNumber)\" could not be converted to an integer")
}

如果 Int(possibleNumber) 返回的可选整数有值,则设置一个名为 actualNumber 的新常量为可选整数中包含的值。

如果转换成功,就可以在 If 语句中使用 actualNumber 常量。如果想在 If 语句的第一个分支中操作 actualNumber 的值,则可以编写 If var actualNumber,而可选语句中包含的值将作为变量而不是常量可用。

隐式解包

有时候很明显一个 optional 第一次被赋值后是肯定有值的,这时候就可以将其定义为隐式展开的可选值。通过在要使其为可选类型的后面放置感叹号(字符串!)而不是问号(字符串?),在使用时,不需要在它的名称后面加上感叹号。

隐式展开的可选值在幕后是一个普通的可选值,但也可以像非可选值一样使用,而不需要在每次访问可选值时展开它。下面的例子展示了可选字符串和隐式展开的可选字符串在以显式字符串的形式访问其包装后的值时的行为差异:

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation point

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation point

在上面的代码中,可选值 assumedString 在将其值赋给 implicitString 之前被强制解包装,因为 implicitString 具有显式的、非可选的字符串类型。在下面的代码中,optionalString 没有明确的类型,所以它是一个普通的可选类型:

let optionalString = assumedString
// The type of optionalString is "String?" and assumedString isn't force-unwrapped.

optionalString 的类型是 "String?" 并且 assumedString 不是强制解包装的。

如果一个隐式展开的可选对象是 nil,并且你试图访问它的包装值,将触发一个运行时错误。结果与在不包含值的普通可选选项后面放置感叹号完全相同。可以检查一个隐式展开的可选对象是否为 nil,就像检查一个普通的可选对象一样:

if assumedString != nil {
    print(assumedString!)
}

也可以使用可选绑定来进行隐式解包:

if let definiteString = assumedString {
    print(definiteString)
}

docs.swift.org/swift-book/…