原文: https://www.programiz.com/swift-programming/optionals

在本文中,您将学习可选项,其用例以及 Swift 中的可选项处理。

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

示例

  1. let someValue = Int()
  2. print(someValue)

运行该程序时,输出为:

  1. 0

但是,Swift 中还有另一种称为Optional的数据类型,其默认值为空值(nil)。 如果希望变量或常量中不包含任何值,则可以使用可选项。 可选项可以包含一个值或不存在一个值(空值)。

从技术上讲,您可以认为它是可选的鞋盒。 鞋盒中可能装有鞋,也可能没有。 因此,从包装箱中取出鞋子时,您应该事先知道。


如何声明Optional

通过将!?附加到Type,您可以简单地将数据类型表示为Optional。 如果一个可选参数中包含一个值,则返回值为Optional<Value>,否则返回nil

示例 1:如何在 Swift 中声明一个可选项?

  1. var someValue:Int?
  2. var someAnotherValue:Int!
  3. print(someValue)
  4. print(someAnotherValue)

运行该程序时,输出为:

  1. nil
  2. nil

在上面的程序中,我们使用?!初始化了一个可选项。 两种方法都是可以创建可选项的方法,但是有一个主要的不同,我们将在下面进行探讨。

声明一个可选的Int意味着该变量将具有整数值或无值。 由于没有为变量分配任何值,因此您可以在屏幕上看到两个print语句输出nil


示例 2:从可选项分配和访问值

  1. let someValue:Int? = 5
  2. print(someValue)
  3. print(someValue!)

运行该程序时,输出为:

  1. Optional(5)
  2. 5

在上面的程序中,我们声明了Int类型的可选项,并在其中分配了值 5。

如您所见,将可选项打印为print(someValue)不会给您5而是Optional(5)。 它具有上述形式:Optional<Value>。 为了从中访问<Value>,我们需要一种称为展开的机制。

您可以通过在变量/常量的末尾附加!字符来展开可选字符,如下一行print(someValue!)所示。print(someValue!)打开包装,并在屏幕上输出5

但是,请记住,仅当确定在访问可选项时肯定具有值时,才应使用这种解包机制。


示例 3:显式声明一个未包装的可选项

您还可以通过以下方式创建解包后的可选项:

  1. let someValue:Int! = 5
  2. print(someValue)

运行该程序时,输出为:

  1. 5

在上面的程序中,Int!创建一个未包装的可选项,当您访问它时,它会自动对值进行包装,因此您不必每次都附加!字符。

请确保在使用这些可选项时,变量在访问它时始终需要有一个值。 如果不这样做,将会导致致命的错误崩溃。


示例 4:访问null的未包装可选对象时发生致命错误

  1. var someValue:Int!
  2. var unwrappedValue:Int = someValue //crashes due to this line

当您运行该程序时,您会因致命错误而崩溃:在解开可选项时意外发现nil,因为代码unwrappedValue:Int = someValue试图将可选someValue中的值赋给变量unwrappedValue

但是,somevalue是包含nil值的Optional类型。 尝试将nil值分配给变量unwrappedValue(这不是可选的)会导致崩溃。

有多种处理此情况的技术,下面将进行说明。


可选项处理

为了使用可选项,需要将其解包。 使用可选项的更好方法是通过条件展开而不是使用!运算符强制展开。

这是因为有条件的展开询问检查此变量是否具有值?。 如果是,请提供该值,否则将处理nil情况。

相反,强制展开表示该变量在使用时确实有一个值。 因此,当您强制解开一个nil的变量时,您的程序将在解开可选异常并抛出的同时抛出意外发现的nil。 下面说明了一些用于条件展开的技术:

1. If语句

您可以使用if语句,然后将可选参数与nil进行比较,以找出可选参数是否包含值。 您可以在if语句中使用比较运算符“等于”运算符(==)或“不等于”运算符(!=)。

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

  1. var someValue:Int?
  2. var someAnotherValue:Int! = 0
  3. if someValue != nil {
  4. print("It has some value \(someValue!)")
  5. } else {
  6. print("doesn't contain value")
  7. }
  8. if someAnotherValue != nil {
  9. print("It has some value \(someAnotherValue!)")
  10. } else {
  11. print("doesn't contain value")
  12. }

运行该程序时,输出为:

  1. doesn't contain value
  2. It has some value 0

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


2.可选绑定(如果允许)

可选绑定可帮助您找出可选项是否包含值。 如果可选项包含一个值,则该值可用作临时常量或变量。 因此,可以将可选绑定与if语句一起使用,以检查可选项内部的值,并在单个操作中将该值提取到常量或变量中。

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

  1. var someValue:Int?
  2. var someAnotherValue:Int! = 0
  3. if let temp = someValue {
  4. print("It has some value \(temp)")
  5. } else {
  6. print("doesn't contain value")
  7. }
  8. if let temp = someAnotherValue {
  9. print("It has some value \(temp)")
  10. } else {
  11. print("doesn't contain value")
  12. }

运行该程序时,输出为:

  1. doesn't contain value
  2. It has some value 0

在上面的程序中,如果可选项包含一个值,则执行if语句中的代码。 否则,else块将被执行。if-let语句还自动展开该值,并将展开后的值放入temp常量中。 该技术的主要优势在于,尽管可以确定某个可选项包含一个值,但您无需强行解开该值。


3.guard语句

您可以使用guard处理 Swift 中的可选项。 如果您不知道什么警卫,请不要担心。 现在,仅将警卫视为没有if块的if-else条件。 如果条件失败,则执行else语句。 如果不是,则执行下一条语句。 有关更多详细信息,请参见 Swift Guard

示例 6:使用guard的可选项处理

  1. func testFunction() {
  2. let someValue:Int? = 5
  3. guard let temp = someValue else {
  4. return
  5. }
  6. print("It has some value \(temp)")
  7. }
  8. testFunction()

运行该程序时,输出为:

  1. It has some value 5

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


4.nil折叠运算符

在 Swift 中,您还可以使用nil折叠运算符检查可选变量是否包含值。 定义为(a ?? b)。 它解开可选的a并返回它(如果它包含一个值),或者如果a为零,则返回默认值b

示例 7:使用nil折叠运算符的可选项处理

  1. var someValue:Int!
  2. let defaultValue = 5
  3. let unwrappedValue:Int = someValue ?? defaultValue
  4. print(unwrappedValue)

运行该程序时,输出为:

  1. 5

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

  1. var someValue:Int? = 10
  2. let defaultValue = 5
  3. let unwrappedValue:Int = someValue ?? defaultValue
  4. print(unwrappedValue)

运行该程序时,输出为:

  1. 10

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