首页 理论教育 实战解析:可空类型的使用

实战解析:可空类型的使用

时间:2023-06-23 理论教育 版权反馈
【摘要】:Swift的可空类型让这门语言更加安全。一个可能为nil的实例应该被声明为可空类型。使得optional String成为可空的String类型。动手写3.4.9 UnwrappingOptional控制台输出如下:强制展开会访问可空实例封装的值,这样就能把“Unwrapping Me”取出。动手写3.4.10 OptionalBindingbindedString变成了条件语句的第一个分支中的临时变量,如果可空类型不是nil,那么就会将值赋给这个临时变量。实际上,因为隐式展开可空类型安全性较差,所以如果读者不明确指出想要使用隐式展开可空类型,Swift

实战解析:可空类型的使用

可空类型或者称可选类型(Optional)是Swift独有的特性,用来表示某个变量可能是空的。如果读者遇上一个可空类型,那么这个对象要么已经有值,要么可能就是nil(没有值的表示)。本节讲述如何声明可空类型,如何使用可空对象绑定(optional binding)来检查某个可空对象是否为nil并且在有值的情况下使用值,以及如何使用可空类型的链式调用(optional chaining)来查询一连串可空值。

Swift的可空类型让这门语言更加安全。一个可能为nil的实例应该被声明为可空类型。这意味着如果一个实例没有被声明为可空类型,它就不可能是nil。通过这种方式,编译器就能知道一个实例是否可能为nil。这种显式声明可以让代码更具表达能力,也更安全。现在我们来看看如何声明可空类型。

动手写3.4.8 DefineOptional

控制台输出如下:

首先声明一个名为“optionalString”的变量用来存储一个字符串。接着,显式声明optional String的类型是String,跟之前的形式略有不同,这次在String后面加了“?”,“?”使得optional String成为可空的String类型。声明完之后先打印一下这个变量,结果是个nil。赋值完之后再打印一下,结果是Optional("I am optional String.")。打印出来说明是个Optional的对象,里面存放着一个字符串。我们注意到,这里在print中还增加了“as Any”,这是编译器提醒需要加上的,不然会有警告信息,因为可空类型的判断只能在运行时进行。

这个时候如果需要把这个可空对象赋值给其他变量,就要将这个对象的值取出。可空类型的取值有两种:强制展开(即在一个可空类型之后加一个感叹号)和实例绑定。下面我们来分别介绍这两种方式的使用。

动手写3.4.9 UnwrappingOptional

控制台输出如下:

强制展开会访问可空实例封装的值,这样就能把“Unwrapping Me”取出。强制展开的时候,无论是否有值都会去访问变量的值;如果没有值,展开会产生运行时错误。强制展开具有一定的危险性,有可能会在程序运行时触发陷阱,所以本书建议读者谨慎和节制地使用强制展开。

既然如此那为何还要用强制展开呢?我们首先要建立一个正确的认知:String和String?并不是同一个类型。如果想把一个String?的值赋给一个String变量,一定要将可空类型的值取出才能成功赋值。但是若每次赋值之前都要进行非nil判断再进行展开,代码上就会显得有些啰唆,于是就有了第二种取值方法——实例绑定。

实例绑定是一种固定模式,这对于判断可空对象是否有值很有用。如果有值,就将其赋给一个临时常量或变量,并且使这个常量或变量在条件语句的第一个分支代码中可用,这样可以让代码更简洁,同时保持代码的自描述性。

动手写3.4.10 OptionalBinding

控制台输出如下:

强制展开会访问可空实例封装的值,这样就能把“Unwrapping Me”取出。强制展开的时候,无论是否有值都会去访问变量的值;如果没有值,展开会产生运行时错误。强制展开具有一定的危险性,有可能会在程序运行时触发陷阱,所以本书建议读者谨慎和节制地使用强制展开。

既然如此那为何还要用强制展开呢?我们首先要建立一个正确的认知:String和String?并不是同一个类型。如果想把一个String?的值赋给一个String变量,一定要将可空类型的值取出才能成功赋值。但是若每次赋值之前都要进行非nil判断再进行展开,代码上就会显得有些啰唆,于是就有了第二种取值方法——实例绑定。

实例绑定是一种固定模式,这对于判断可空对象是否有值很有用。如果有值,就将其赋给一个临时常量或变量,并且使这个常量或变量在条件语句的第一个分支代码中可用,这样可以让代码更简洁,同时保持代码的自描述性。

动手写3.4.10 OptionalBinding

bindedString变成了条件语句的第一个分支中的临时变量,如果可空类型不是nil,那么就会将值赋给这个临时变量。如果条件计算为真,其执行的代码块就可以使用这个变量,此外,不需要再强制展开可空对象了。如果转换成功,那么这个操作是自动完成的,可空对象的值就在这个条件语句声明的变量中。这里补充一种可空类型,叫隐式展开可空类型。这类可空类型的取值方法和一般可空类型相比有个很大的差别,就是不需要强制展开,而是在赋值到其他变量时自动展开的。具体可参看如下代码:(www.xing528.com)

动手写3.4.11 ImplicitlyUnwrappedOptional

控制台输出如下:

bindedString变成了条件语句的第一个分支中的临时变量,如果可空类型不是nil,那么就会将值赋给这个临时变量。如果条件计算为真,其执行的代码块就可以使用这个变量,此外,不需要再强制展开可空对象了。如果转换成功,那么这个操作是自动完成的,可空对象的值就在这个条件语句声明的变量中。这里补充一种可空类型,叫隐式展开可空类型。这类可空类型的取值方法和一般可空类型相比有个很大的差别,就是不需要强制展开,而是在赋值到其他变量时自动展开的。具体可参看如下代码:

动手写3.4.11 ImplicitlyUnwrappedOptional

控制台输出如下:

控制台输出如下:

这里的可空类型是用“!”声明的,表示这是一个隐式展开可空类型。不过要注意,这种自动展开的便利性也伴随着一定的危险性:如果隐式展开可空实例没有值的话,访问其值会导致运行时错误。其中第三行代码,使用两个斜杠“//”表明这一行是注释,斜杠后面的文字不会参与代码的执行,仅仅是被读者所看到,在下一小节中我们会详细介绍注释。如果第三行代码不是注释,而是真正被执行的语句,那么就会产生一个运行时的错误,因为implicitlyOptionalString还未被赋值就隐式展开。为此,建议只要某个实例有可能是nil,就不使用隐式展开可空类型。实际上,因为隐式展开可空类型安全性较差,所以如果读者不明确指出想要使用隐式展开可空类型,Swift的编译器就会提供一个普通的可空类型。出于程序的稳定性,建议只在特殊情况下使用隐式展开可空类型,比如一个类的初始化阶段,后续章节会进行解释。

最后介绍一下可空类型的链式调用。与可空对象绑定一样,可空类型的链式调用提供了一种对可空对象进行查询以判断其是否包含值的机制。两者的一个重要区别是,可空链式调用允许开发者把多个查询语句合并为一个可空实例的值。如果链式调用中的每个可空对象都包含值,那么每个调用都会成功,整个查询链会返回期望类型的可空实例;如果查询链中的任意可空实例是nil,那么整个链式调用会返回nil。

动手写3.4.12 OptionalChaining

这里的可空类型是用“!”声明的,表示这是一个隐式展开可空类型。不过要注意,这种自动展开的便利性也伴随着一定的危险性:如果隐式展开可空实例没有值的话,访问其值会导致运行时错误。其中第三行代码,使用两个斜杠“//”表明这一行是注释,斜杠后面的文字不会参与代码的执行,仅仅是被读者所看到,在下一小节中我们会详细介绍注释。如果第三行代码不是注释,而是真正被执行的语句,那么就会产生一个运行时的错误,因为implicitlyOptionalString还未被赋值就隐式展开。为此,建议只要某个实例有可能是nil,就不使用隐式展开可空类型。实际上,因为隐式展开可空类型安全性较差,所以如果读者不明确指出想要使用隐式展开可空类型,Swift的编译器就会提供一个普通的可空类型。出于程序的稳定性,建议只在特殊情况下使用隐式展开可空类型,比如一个类的初始化阶段,后续章节会进行解释。

最后介绍一下可空类型的链式调用。与可空对象绑定一样,可空类型的链式调用提供了一种对可空对象进行查询以判断其是否包含值的机制。两者的一个重要区别是,可空链式调用允许开发者把多个查询语句合并为一个可空实例的值。如果链式调用中的每个可空对象都包含值,那么每个调用都会成功,整个查询链会返回期望类型的可空实例;如果查询链中的任意可空实例是nil,那么整个链式调用会返回nil。

动手写3.4.12 OptionalChaining

控制台输出如下:

控制台输出如下:

使用“?.”的方法调用进行对可空类型的链式调用,如果可空类型没有值就返回nil,否则就拿出值进行接下来的方法调用。

使用“?.”的方法调用进行对可空类型的链式调用,如果可空类型没有值就返回nil,否则就拿出值进行接下来的方法调用。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈