我们使用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. Mysql binlog二进制日志

    Mysql binlog日志有三种格式,分别为Statement,MiXED,以及ROW! 1.Statement:每一条会修改数据的实际原sql语句都会被记录在binlog中. 优点:不需要记录每一 ...

  2. Eclipse json文件报错

    只要找一个json在线解析,验证你的json文件格式的正确性,错误可以忽略. 如要消除红叉,关闭Json Validation即可,如下操作: Window > Preferences > ...

  3. Scala语言学习笔记(3)

    类 // 定义并使用类 class User val user1 = new User // 主体构造器(primary constructor) class Point(var x: Int, va ...

  4. Linux CentOS7中 设置IP地址、网关DNS

    cd  /etc/sysconfig/network-scripts/  #进入网络配置文件目录 vi  ifcfg-eno16777736  #编辑配置文件,此处eno后边的编号因电脑而易 TYPE ...

  5. 数据类型-Series

    数据类型-Series Series数据类型由一组数据和数据相关的索引组成,键 -> 值 Series数据类型可视为:一维 带标签 数组 Series基本操作类似数组和字典 Series数据类型 ...

  6. Eclipse出现错误:The selection cannot be launched,and there are no recent launches

    刚装了eclipse,想写个Java程序测试一下能不能用,结果一run就出现错误,Debug也是同样的错误,错误内容为:the selection cannot be launched,and the ...

  7. spring中配置监听队列的MQ

    一.spring中配置监听队列的MQ相关信息注:${}是读取propertites文件的常量,这里忽略.绿色部分配置在接收和发送端都要配置.  <bean id="axx" ...

  8. (一)ROS的安装与环境配置

    1.设置教程 1.1 打开system setting(系统设置)->Software&Updates(软件与更新) 1.2点击上方Other software(其他软件),点击左下角a ...

  9. centos6.6 下 安装 nginx

    1.安装nginx需要pcre的依赖,请安装好pcre.假设安装目录如下: /usr/local/pcre-8.38 源码目录如下: /usr/src/pcre-8.38 2.下载nginx安装压缩包 ...

  10. 表单提交的两种请求方式:post与get。post与get两者的对比分析

    post与get两者的对比分析: