在上一篇文章中,我们了解了 Swift 中可用的不同数据类型,并注意到那些类型的变量或常量包含一个默认值。
示例
let someValue = Int() print(someValue)
运行程序后,输出将是
0
然而,Swift 中还有另一种名为 Optional 的数据类型,其默认值为 null 值 (nil
)。当您希望变量或常量不包含任何值时,可以使用可选类型。可选类型可能包含一个值,也可能不包含一个值(null 值)。
非技术性地说,您可以将可选类型视为一个鞋盒。鞋盒可能装有鞋子,也可能不装有鞋子。因此,在从鞋盒中取出鞋子之前,您应该提前知道。
如何声明可选类型?
您可以通过在 Type
后面附加 !
或 ?
来简单地将数据类型表示为 Optional。如果可选类型包含值,它将返回 Optional<Value>
形式的值,如果不包含,则返回 nil
。
示例 1:如何在 Swift 中声明可选类型?
var someValue:Int?
var someAnotherValue:Int!
print(someValue)
print(someAnotherValue)
运行程序后,输出将是
nil nil
在上面的程序中,我们使用 ?
和 !
初始化了一个可选类型。这两种方式都可以创建可选类型,但它们之间有一个主要区别,我们将在下面探讨。
声明一个可选的 Int 意味着该变量将有一个整数值或没有值。由于未为变量分配值,您可以看到两个 print
语句都在屏幕上输出了 nil
。
示例 2:从可选类型中赋值和访问值
let someValue:Int? = 5
print(someValue)
print(someValue!)
运行程序后,输出将是
Optional(5) 5
在上面的程序中,我们声明了一个 Int
类型的可选类型,并为其赋了值 5。
正如您所见,打印可选类型 print(someValue)
并不会得到 5
,而是 Optional(5)
。它的形式如上所述:Optional<Value>
。为了访问其中的 <Value>
,我们需要一种称为解包的机制。
您可以通过在变量/常量末尾附加 !
字符来解包可选类型,如下一行 print(someValue!)
。print(someValue!)
会解包可选类型并在屏幕上输出 5
。
但是,请记住,只有当您确定在访问可选类型时它肯定会有一个值时,才应使用这种解包机制。
示例 3:显式声明一个已解包的可选类型
您也可以创建已解包的可选类型,如下所示:
let someValue:Int! = 5
print(someValue)
运行程序后,输出将是
5
在上面的程序中,Int!
创建了一个已解包的可选类型,当您访问它时,它会自动解包该值,这样您就不必每次都附加 !
字符了。
使用这些类型的可选类型时要格外小心,访问变量时它始终需要有一个值。否则,您将收到一个致命错误崩溃。
示例 4:访问已解包的空可选类型时发生致命错误
var someValue:Int!
var unwrappedValue:Int = someValue //crashes due to this line
运行程序时,您会收到一个崩溃,错误信息为 fatal error: unexpectedly found nil while unwrapping an Optional value,因为代码 unwrappedValue:Int = someValue
尝试将可选值 someValue 的值赋给变量 unwrappedValue。
但是,someValue 是一个包含 nil
值的 Optional
类型。尝试将 nil 值赋给不是可选类型的变量 unwrappedValue 将导致崩溃。
有不同的技术可以处理这种情况,下面将进行解释。
可选类型处理
为了使用可选类型的值,需要对其进行解包。使用可选类型值的更好方法是条件解包,而不是使用 !
运算符强制解包。
这是因为条件解包会询问“这个变量有值吗?”。如果有,则返回该值,否则会处理 nil 情况。
相反,强制解包表示“您在使用此变量时,它肯定有一个值。”。因此,当您强制解包一个值为 nil 的变量时,您的程序将抛出unexpectedly found nil while unwrapping an optional 异常并崩溃。以下是一些条件解包技术的解释
1. If 语句
您可以使用 if 语句并将可选类型与 nil 进行比较,以确定可选类型是否包含值。您可以在 if 语句中使用“等于”运算符 (==
) 或“不等于”运算符 (!=
)。
示例 5:使用 if else 语句处理可选类型
var someValue:Int?
var someAnotherValue:Int! = 0
if someValue != nil {
print("It has some value \(someValue!)")
} else {
print("doesn't contain value")
}
if someAnotherValue != nil {
print("It has some value \(someAnotherValue!)")
} else {
print("doesn't contain value")
}
运行程序后,输出将是
doesn't contain value It has some value 0
在上面的程序中,如果可选类型包含值,则执行 if 语句中的代码,否则执行 else 块中的语句。使用此技术处理可选类型的主要缺点是,您仍然需要使用 !
运算符从可选类型中解包值。
2. Optional Binding (if-let)
Optional binding 帮助您确定可选类型是否包含值。如果可选类型包含值,则该值将作为临时常量或变量可用。因此,Optional binding 可以与 if 语句一起使用,以检查可选类型中的值,并将该值在一个操作中提取到常量或变量中。
示例 5:使用 if let 语句处理可选类型
var someValue:Int?
var someAnotherValue:Int! = 0
if let temp = someValue {
print("It has some value \(temp)")
} else {
print("doesn't contain value")
}
if let temp = someAnotherValue {
print("It has some value \(temp)")
} else {
print("doesn't contain value")
}
运行程序后,输出将是
doesn't contain value It has some value 0
在上面的程序中,如果可选类型包含值,则执行 if 语句中的代码。否则,将执行 else 块。if-let
语句还会自动解包该值,并将解包后的值放入 temp 常量中。此技术具有主要优点,因为您不必强制解包值,即使您确信可选类型包含值。
3. Guard 语句
您可以使用 guard 来处理 Swift 中的可选类型。如果您不知道 guard 是什么,请不要担心。现在,您可以将 guard 视为一个没有 if 块的 if-else
条件。如果条件失败,则执行 else 语句。否则,执行下一条语句。有关更多详细信息,请参阅 Swift guard。
示例 6:使用 guard-let 处理可选类型
func testFunction() {
let someValue:Int? = 5
guard let temp = someValue else {
return
}
print("It has some value \(temp)")
}
testFunction()
运行程序后,输出将是
It has some value 5
在上面的程序中,guard 包含一个条件,即可选值 someValue 是否包含值。如果它包含值,则 guard-let
语句会自动解包该值,并将解包后的值放入 temp 常量中。否则,将执行 else 块,它将返回到调用函数。由于可选类型包含值,因此会调用 print
函数。
4. Nil-coalescing 运算符
在 Swift 中,您还可以使用 nil-coalescing 运算符来检查可选类型是否包含值。它定义为 (a ?? b)
。它会解包可选值 a,如果 a 包含值,则返回 a,如果 a 为 nil,则返回默认值 b。
示例 7:使用 nil-coalescing 运算符处理可选类型
var someValue:Int!
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)
运行程序后,输出将是
5
在上面的程序中,变量 someValue 被定义为可选类型并包含 nil 值。nil coalescing 运算符未能解包该可选类型,因此返回 defaultValue。因此,语句 print(unwrappedValue)
在控制台中输出了 5。
var someValue:Int? = 10
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)
运行程序后,输出将是
10
但是,在上面的程序中,可选变量 someValue 被初始化为值 10。因此,nil coalescing 运算符成功地从 someValue 中解包了该值。因此,语句 someValue ?? defaultValue
返回 10,语句 print(unwrappedValue)
在控制台中输出了 10。