Swift 可选类型(Optional)

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

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

例:

let someValue = Int()
print(someValue)

运行该程序时,输出为:

0

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

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

如何声明一个可选的?

您可以通过追加将数据类型简单地表示为 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>,我们需要一种称为解包(unwrapping)的机制。

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

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

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

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

let someValue:Int! = 5
print(someValue)

运行该程序时,输出为:

5

在上面的程序中,Int! 创建一个未包装的可选内容,当您访问它时,它会自动解包该值,因此您不必每次都!字符。

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

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

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

当您运行该程序时,您将得到致命错误的崩溃:解开Optional值时意外发现nil,因为代码unwrappedValue:Int = someValue试图将Optional someValue中的值分配给变量unwrappedValue。

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

下面将说明处理此情况的不同方法。

可选处理

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

这是因为有条件的展开询问是否检查此变量是否有值?。如果是,请提供该值,否则将处理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-else没有if阻止的条件。如果条件失败,则执行else语句。如果不是,则执行下一条语句。有关更多详细信息,请参见Swift Guard

示例6:使用Guard的可选处理

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 函数。更多细节请参见Swift guard。

4.空合运算符(??)

在Swift中,您还可以使用空合运算符运算符检查可选项是否包含值。 它被定义为(a??b)。 它展开一个可选的a,如果它包含一个值,则返回它,或者如果a为空,则返回默认值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。