我们使用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类型的更多相关文章

  1. Swift中的Optional类型 (可选类型)与强制解包 ? !

    我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...

  2. Swift(一,创建对象,类型推导,基本运算,逻辑,字符串,数组,字典)

    swift用起来刚开始感觉有点怪怪的,但用了一段时间觉得还是挺好用的,哈哈.毕竟都是要有一个过程的嘛. 我就写一些自己在使用swift的时候的注意点吧,如有不正之处,还请指正! 一.在开发中优先使用常 ...

  3. Swift 语言附注 类型

    本页包括内容: 类型注解(Type Annotation) 类型标识符(Type Identifier) 元组类型(Tuple Type) 函数类型(Function Type) 数组类型(Array ...

  4. Swift - 关于 Optional 的一点唠叨

    Optional 是 Swift 的一个非常重要的特性,它除了提供类型安全的机制,也是 Swift 中很多语言特性的核心.当然,使用 Optional 时也要了解很多坑,这样能帮助我们更好的运用它. ...

  5. Swift 可选(Optionals)类型

    Swift 的可选(Optional)类型,用于处理值缺失的情况.可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值". Swfit语言定义后缀?作为命 ...

  6. [Swift]遍历集合类型(数组、集合和字典)

    Swift提供了三种主要的集合类型,称为数组,集合和字典,用于存储值集合. 数组是有序的值集合. 集是唯一值的无序集合. 字典是键值关联的无序集合. Swift中无法再使用传统形式的for循环. // ...

  7. Swift中的类型属性(静态变量)

    http://blog.haohtml.com/archives/15098 Swift中的类型属性(静态变量) Posted on 2014/06/13 类型属性语法 在 C 或 Objective ...

  8. Swift中可选类型(Optional)的用法 以及? 和 ! 的区别 (转载博客,知识分享)

    本文转载自:代码手工艺人的博客,原文名称:Swift之 ? 和 ! Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之 ...

  9. iOS开发零基础--Swift教程 可选类型

    可选类型的介绍 注意: 可选类型时swift中较难理解的一个知识点 暂时先了解,多利用Xcode的提示来使用 随着学习的深入,慢慢理解其中的原理和好处 概念: 在OC开发中,如果一个变量暂停不使用,可 ...

随机推荐

  1. 快快快!27个提升效率的iOS开源库推荐(转)

    CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用.开发工具.移动游戏及引擎.智能硬件.物联网等方方面面.如果您想投稿.参与内容翻译工作,或寻求近匠报道,请发送 ...

  2. MySQLReport

    简介: MySQLReport 一.安装 shell > yum -y install mysqlreport perl-DBD-MySQL 二.使用 shell > mysqlrepor ...

  3. Nginx 错误汇总

    1. Upstream timed out (110: Connection timed out) while reading response header from upstream 这种情况主要 ...

  4. UGUI Auto Layout 自动布局

    Layout Element 首先分配 Minimum Size 如果还有足够空间,分配 Preferred Size 如果还有额外空间,分配 Flexible Size 比较特别的是 Flexibl ...

  5. [ERR] Not all 16384 slots are covered by nodes.

    redis集群开不起来,用redis-cli连接的时候出现如下错误: CLUSTERDOWN The cluster is down 然后使用redis-trib.rb检查: ./redis-trib ...

  6. CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc

    1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在up ...

  7. mac版IDEA使用maven的问题

    在idea中执行maven碰到这个错误:invalid target release: 1.7.首先做了以下操作 1.查看$JAVA_HOME echo $JAVA_HOME /Library/Jav ...

  8. Ubuntu 安装 Zabbix 3.2详细步骤

    创建 zabbix 用户 因为zabbix 程序的守护进程需要非特权用户,所以需要创建一个 zabbix 用户,即使从 root 用户启动 zabbix 程序,也会自动切换到 zabbix 用户,所以 ...

  9. spring JPA分页排序条件查询

    @RequestMapping("/listByPage") public Page<Production> listByPage(int page, int size ...

  10. java学习笔记----@Override的作用

    初学java或多或少都会有这样的疑问,@Override有什么用,有的时候写,有的时候又不写,搞的初学者甚是郁闷. 做了一两年的开发说起这个问题不一定能够对答如流.小弟才疏学浅,花了点时间,看了一下资 ...