跳到主要内容

Swift 可选类型

提示
  1. 可选类型的概念:Swift 中的可选类型(Optional)允许变量包含值或为空(nil),类似于一个可能空的鞋盒。
  2. 声明和解包可选类型:可选类型通过在类型后添加?!声明;解包(访问值)需用!,但只在确定有值时使用以避免崩溃。
  3. 安全处理可选类型:可选类型安全处理方法包括使用if-letguard-let语句检查值的存在,以及使用空合运算符??提供默认值。

[在上一篇文章中,我们学习了 Swift 中可用的不同数据类型,并注意到声明为这些类型的变量或常量包含一个默认值。

示例:

let someValue = Int()
print(someValue)

当你运行程序时,输出将是:

0

然而,Swift 中还有另一种数据类型称为可选类型(Optional),其默认值是一个空值(nil)。当你希望一个变量或常量中不包含任何值时,可以使用可选类型。可选类型可能包含一个值或没有值(一个空值)。

非技术性地讲,你可以将可选类型想象为一个鞋盒。鞋盒可能包含或不包含鞋子。因此,在从盒子里取鞋子之前,你应该提前知道。

如何声明一个可选类型?

你可以通过在 Type 后追加 !? 来简单地表示一个数据类型为可选类型。如果一个可选类型包含一个值,它会返回 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 // 由于这行代码而崩溃

当你运行程序时,会遇到崩溃,因为 致命错误:在解包可选项值时意外发现 nil,这是因为代码 unwrappedValue:Int = someValue 试图将可选项 someValue 的值分配给变量 unwrappedValue

然而,someValue 是一个包含 nil 值的 Optional 类型。尝试将 nil 值分配给非可选项的变量 unwrappedValue 将导致崩溃。

下面解释了处理这种情况的不同技巧。

可选项处理

为了使用可选项的值,它需要被解包。使用可选值的更好方式是通过条件解包而不是使用 ! 运算符强制解包。

这是因为条件解包询问 这个变量有值吗?。如果有,就给出这个值,否则它将处理 nil 情况。

相反,强制解包说 当你使用这个变量时,它确实有值。因此,当你强制解包一个为 nil 的变量时,你的程序会抛出 在解包可选项时意外发现 nil 的异常并崩溃。以下是一些条件解包的技术:

1. If 语句

你可以使用 if 语句并将可选项与 nil 比较,以找出可选项是否包含值。你可以在 if 语句中使用“等于”运算符 (==) 或“不等于”运算符 (!=)。

示例 5:使用 if else 语句处理可选项

var someValue:Int?
var someAnotherValue:Int! = 0

if someValue != nil {
print("它有一些值 \(someValue!)")
} else {
print("不包含值")
}

if someAnotherValue != nil {
print("它有一些值 \(someAnotherValue!)")
} else {
print("不包含值")
}

当你运行程序时,输出将是:

不包含值
它有一些值 0

在上述程序中,如果可选项包含值,则 if 语句内的代码将执行,否则将执行 else 块内的语句。使用这种技术处理可选项的主要缺点是,你仍然需要使用 ! 运算符从可选项中解包值。

2. 可选绑定(if-let)

可选绑定可以帮助你找出可选项是否包含值。如果一个可选项包含值,那么这个值可以作为临时常量或变量使用。因此,可以将可选绑定与 if 语句一起使用,以检查可选项中是否有值,并将该值提取到一个常量或变量中,只需一次操作即可。

示例 5:使用 if let 语句处理可选项

var someValue:Int?
var someAnotherValue:Int! = 0

if let temp = someValue {
print("它有一些值 \(temp)")
} else {
print("不包含值")
}

if let temp = someAnotherValue {
print("它有一些值 \(temp)")
} else {
print("不包含值")
}

当你运行程序时,输出将是:

不包含值
它有某个值 0

在上述程序中,如果可选类型包含一个值,则 if 语句内的代码将被执行。否则,将执行 else 块。if-let 语句还会自动解包该值,并将解包后的值放在 temp 常量中。这种技术具有重要优势,因为即使确定可选类型包含一个值,你也不需要强制解包该值。

3. Guard 语句

你可以在 Swift 中使用 guard 来处理可选类型。如果你不知道 guard 是什么,也不用担心。现在,只需将 guard 想象为没有 if 块的 if-else 条件。如果条件失败,则执行 else 语句。如果不是,则执行下一个语句。有关更多详情,请参阅 Swift guard

示例 6:使用 guard-let 处理可选类型

func testFunction() {
let someValue:Int? = 5
guard let temp = someValue else {
return
}
print("它有某个值 \(temp)")
}

testFunction()

当你运行程序时,输出将是:

它有某个值 5

在上述程序中,guard 包含一个条件,即可选类型 someValue 是否包含一个值。如果它包含一个值,那么 guard-let 语句将自动解包该值,并将解包后的值放在 temp 常量中。否则,将执行 else 块,并返回到调用函数。由于可选类型包含一个值,因此调用了 print 函数。

4. 空合运算符

在 Swift 中,你还可以使用空合运算符来检查可选类型是否包含值。它定义为 (a ?? b)。它解包一个可选类型 a 并返回它(如果它包含一个值),或者如果 a 为 nil,则返回默认值 b

示例 7:使用空合运算符处理可选类型

var someValue:Int!
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)

当你运行程序时,输出将是:

5

在上述程序中,变量 someValue 被定义为可选类型并包含 nil 值。空合运算符无法解包可选类型,因此返回 defaultValue。因此,语句 print(unwrappedValue) 在控制台输出 5。

var someValue:Int? = 10
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)

当你运行程序时,输出将是:

10

然而,在上述程序中,可选变量 someValue 被初始化为值 10。因此,空合运算符成功地从 someValue 中解包出值。因此,语句 someValue ?? defaultValue 返回 10,语句 print(unwrappedValue) 在控制台输出 10。