Swift的Optional类型
我们使用Swift这个苹果新推出的编程语言已经有一段时间了。其中的一个极大的优点就是苹果称为“optional types”的东西。几乎所有的objective-c程序员都知道用nil来表示某个引用类型的对象是没有值的。但是要把nil和某个变量的类型联系起来还是有些牵强。
这里,我们就来介绍一下Swift提供的optional type(可选类型)。先介绍一些实现的细节,然后指出optional type体系里的几个要点。
类型?
在我们开始进入代码前,先来看看为什么一个类型被定义为可选的。我们遇到的类型一般都是通常的,非可选的类型。包括一般的值类型,比如,Int,Bool和String。还有复杂点的引用类型,比如,UIView,等。
我们声明这些类型的变量的时候,Swift要求必须给这些变量赋值。这一要求非常的严格,如果你想在初始化一个变量之前使用它使编译不过的。

这个表面看起来很郁闷,但其实很有帮助。长远来说,不让这样的代码编译通过,Swift可以避免发生因为使用了未初始化的值而引发的潜在的运行时错误。
let x: Int = nil
然而,有人会尝试给let声明的常量赋值为nil。

这样的代码会直接引发一个错误:类型“Int”不是protocol ’NilLiteralConvertible’类型。对于非optional type的类型,不实现“NilLiteralConvertible”protocol是不可以使用nil来初始化的。所以,简单的x,只是一个Int型的实例,只能被赋值为Int的值而不是nil。
程序里的变量不可能全部都有初值,所以这个时候optional type就该出场了。Swift里,只要在任意类型的后面加一个问号以后就变成了optional type(可控类型)。比如,之前的例子中。只要给Int后面加一个问号就可以将x赋值为nil了。

这应该是很多写Objective-C的哥们需要的了。变量值可以是“实际”的值,也可以是nil。这只取决于你的代码处理的是哪种情况了。
装箱
你可能会说,“Int只是值类型,不是一个对象怎么能使用nil呢?NSInteger是不能这么用得。。”
的确,你说的没错。NSInteger没有nil值。或者更准确的说经过类型转化后你会得到一个整型值0。所以,在Objective-C得API里定义了很多的标记表明“无值”状态:0,1,NSIntergerMin,NSIntegerMax以及NSNotFound等,都是表明“nothing”的。
当你仔细考虑就会发现没有一个一致的方式表明“nothing”这个值,而是用不同的自定义值标记“nothing”会增加一定的复杂度。取一个数组中不存在的值返回的事NSNotFound,取一个table view中不存在的row的时候返回的事一个-1。
Swift的optional type提供了一种更加清晰的表示方法。但是如何让任何类型都具有optional type这个功能呢?这些都建立在泛型的基础之上:

上面的就是Swift核心库对于optional type的定义(稍微作了修改)。Swift定义了一个新的类型Optional,它由两个值,一个是“nothing”,叫做None,一个是把某个类型T的值给包装起来之后的值。Swift就是利用这一机制把某了类型的值包装起来,当然这个值可以是空(nothing),也可以不是空。

在这个例子中, 第一个整数就只是一个Int型的值。后面的类型后面跟了问号“?”的其实都是Optional<T>类型的。或者,简短的可以表示为Int?。
有了这个能力,Swift就可以给任何类型表示“nothing”的值nil,即使是Int。Optional type同时可以表示“real”的值,也可以表示“nothing”的值,而不需要其他的特殊的值。
拆箱
这样表示optional value同时也会引发一个问题。现在我们知道optional type是一个独立的类型:Optional<T>。所以,在需要T的地方,不如某个函数需要T类型的参数传入,那么optional<T>的值是不能用的:

我们需要把需要的值从optional的箱子里拿出来。并且,很重要的一点,在那之前需要检查这个值是否存在。Swift提供了叹号“!”操作符来提取值。

记得把x的值修改为100,而不是之前的nil。因为,叹号操作符只适用于optional type的值本身有“real”值的。如果没有的话是会抛出运行时异常的。
所以,在拆箱取值以前,我们需要先判断这个可选(optional)的值是否为空。就和我们在Objective-C中常做的类似。

但是如果这个x是从其他的方法返回回来的呢?我们可以直接调用这个函数来检验返回值, 完全不必要先给局部变量赋值,再检测是否为空。
Swift已经实现了这个功能,叫做optional binding(可选绑定)。使用if和let两个关键字就可以写出一行紧凑的代码来检测函数返回值是否存在。

这里我们已经不用叹号操作符来显示的强制拆箱。这是optional binding(可选绑定)的另一个好用的地方。直接在if语句的判定表达式里拆箱optional type(可选类型),就可以确定这个optional type是否有值,不用手动的使用叹号操作符来拆箱。
Chaining
现在我们建立一个准确的检测和拆箱optional value(可选值)的规则。比如,如何在optional value上调用方法?你肯定会在一个可能为空的对象上调用方法,这是一定会发生的。在Objective-C中,在nil对象上调用方法会返回一个nil。
幸好Swift也可以做到这样。使用optional chaining(可选链)的方式来调用可能为空(nil)的方法:
在对象和其调用的方法之间插入一个问号“?”操作符,我们就可以表明是要一个实际存在的值还是要一个“nothing”。这和Objective-C的调用非常类似。
注意:这样调用的方法的返回值一定都是optional type(可选类型)的,即使这个方法的返回值被定义为非可选类型(non-optional type)。所以,在optional value(可选值)上调用的方法链上得任意一点的返回值都是optional的。在处理返回值的时候一定要考虑到值可能为空的可能。
考虑下面的代码:
someMethod()方法的声明中制定返回值为Int型,z还是得到一个optional value(可选值)。因为,我们使用了optional chaining(可选链)来调用方法。这可能看起来有点迷惑,但是很有帮助。尤其是在optional binding(可选绑定)的时候。比如,上面代码中的if let z = y?.someMethod()表达式。
这样可以很简洁的处理一下问题:
- 如果y是nil(这里已经是nil),optional chaining(可选链)可以保证我们这样写代码而不报错
- 如果y是nil或者someMethod()方法返回nil,optional binding(可选绑定)不会把nil赋值给non-optional value(非可选值)z。
- 最终我们会得到z,但是不用手动拆箱。因为这是可选绑定的(optional binding)。
总之,对于处理nil值来说,Swift提供了一个非常清晰的系统。我们或得了额外的类型安全,避免了不必要的特殊定义的值,而且还是像Objective-C一样简洁。
Swift的Optional类型的更多相关文章
- Swift中的Optional类型 (可选类型)与强制解包 ? !
我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...
- Swift(一,创建对象,类型推导,基本运算,逻辑,字符串,数组,字典)
swift用起来刚开始感觉有点怪怪的,但用了一段时间觉得还是挺好用的,哈哈.毕竟都是要有一个过程的嘛. 我就写一些自己在使用swift的时候的注意点吧,如有不正之处,还请指正! 一.在开发中优先使用常 ...
- Swift 语言附注 类型
本页包括内容: 类型注解(Type Annotation) 类型标识符(Type Identifier) 元组类型(Tuple Type) 函数类型(Function Type) 数组类型(Array ...
- Swift - 关于 Optional 的一点唠叨
Optional 是 Swift 的一个非常重要的特性,它除了提供类型安全的机制,也是 Swift 中很多语言特性的核心.当然,使用 Optional 时也要了解很多坑,这样能帮助我们更好的运用它. ...
- Swift 可选(Optionals)类型
Swift 的可选(Optional)类型,用于处理值缺失的情况.可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值". Swfit语言定义后缀?作为命 ...
- [Swift]遍历集合类型(数组、集合和字典)
Swift提供了三种主要的集合类型,称为数组,集合和字典,用于存储值集合. 数组是有序的值集合. 集是唯一值的无序集合. 字典是键值关联的无序集合. Swift中无法再使用传统形式的for循环. // ...
- Swift中的类型属性(静态变量)
http://blog.haohtml.com/archives/15098 Swift中的类型属性(静态变量) Posted on 2014/06/13 类型属性语法 在 C 或 Objective ...
- Swift中可选类型(Optional)的用法 以及? 和 ! 的区别 (转载博客,知识分享)
本文转载自:代码手工艺人的博客,原文名称:Swift之 ? 和 ! Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之 ...
- iOS开发零基础--Swift教程 可选类型
可选类型的介绍 注意: 可选类型时swift中较难理解的一个知识点 暂时先了解,多利用Xcode的提示来使用 随着学习的深入,慢慢理解其中的原理和好处 概念: 在OC开发中,如果一个变量暂停不使用,可 ...
随机推荐
- ubuntu sudo apt-get upgrade 和 sudo apt-get dist-upgrade区别
sudo apt-get upgrade: 不会对系统产生重大的影响,可以在任何时候运行. sudo apt-get dist-upgrade: 涉及核心的升级,通常会对系统功能产生实际的影响,可能在 ...
- ArcGIS案例学习笔记2_1
ArcGIS案例学习笔记2_1 联系方式:谢老师,135_4855_4328,xiexiaokui#qq.com 时间:第二天上午 案例1:学校选址 内容:栅格数据分析 教程:pdf page=323 ...
- zabbix3.2的server和zabbix-agent2.2怎么监控MySQL的办法
zabbix官方支持监控MySQL,但直接使用默认的模板是不可用的,还需要经过额外的设置才可以使用.如果只需要对mysql数据库做简单的监控,zabbix自带的模板完全能够满足要求:如果有更高的需求那 ...
- 2021工厂增加2322仓位需求,参与FP分析
在以下语句取消2322工厂即可 INSERT INTO STG.SAP_MARD(MATNR, WERKS, LGORT, LABST, UMLME, INSME, EINME, SPEME, LGO ...
- 实例学习SSIS(一)
网址: http://www.cnblogs.com/tenghoo/archive/2009/10/archive/2009/10/archive/2009/10/archive/2009/10/a ...
- ECMAScript5之JSON对象属性的遍历顺序
测试浏览器 Chrome.Safari 一 键可以用parseInt解析成整数的,按数值升序顺序. var intObj = { '3.3' : 3.3, '2' : 222, '1' :111 } ...
- 4sum, 4sum closest
4sum [抄题]: [思维问题]: 以为很复杂,其实是“排序+双指针”的最高阶模板 [一句话思路]: [输入量特别大怎么办]: [画图]: [一刷]: 先排序! if (i > 0 & ...
- MQ java 基础编程
MQ java 基础编程 编写人:邬文俊 编写时间 : 2006-2-16 联系邮件 : wenjunwu430@gmail.com 前言 通过 2 个多星期对 MQ 学习,在 partner 丁 & ...
- IIS6.0创建新网站后,浏览显示需输入用户名和密码
1.首先我们需要创建一个用于匿名访问的账号. 我的电脑右键,电脑管理->本地用户和组->用户->新用户 注意勾选(用户不能更改密码和密码永不过期这两项) 2.右键新创建的用户-& ...
- 动态加载JS,并执行回调函数
有些时候我们需要动态的加载一些JS,并在JS加载完成后执行一些回调函数. var loadscript = { $$: function (id) { return document.getEleme ...