iOS Developer程序员Programming Language

对 Swift 中可选类型的理解

2018-07-07  本文已影响39人  CoderHG

一、类型定义

OC 中,我们可以这样定义一个变量:

int a = 0;

也可以这样定义:

int a;

这两种定义的方式都是一样的,这里的 一样 是指 是一样的。第二种方式虽然没有显式的指定其值,但是会默认设置一个 0
如果在开发的过程中,我们一定要对这两种情况做区分,应该怎么处理呢?毕竟没有赋值与默认设置一个初始值,还是有所区别的。在 OC 中没有专门的语法支持,当然也是能实现的,只是需要额外的变量来做辅助,特别的麻烦。

OC 中不行,但是在 Swift 中就显得小菜一碟了。多了一种 可选 类型。什么叫可选类型呢?

一个变量没有默认值这一说,要么有值,要么没有值。 这就叫做可选类型。

提示:

Swift 中的可选类型,是一种单独的数据类型。有可选类型,那么就有非可选类型。

定义有如下三种方式:
var a:Optional<Int>
var b:Int?
var c:Int!
以上的 a,b,c 都是可选类型。

但是这两三种定义的方式,也是有异同的,后面再做介绍。

二、如何标识有值与妹纸

上面说了,可选类型的变量,主要针对的是有值还是没有值,两种状态。那么如何来标识呢?

首先来认识一下 OC 中的 nil。代表的是一个空指针,或者是默认指针的值,或者是手动赋值为 nil。总之,给一个指针赋值为 nil, 代表的是一个空值,是一个具体的空值。

但是在 Swift 中就不一样了。只能给一个可选类型的变量赋值为 nil,一旦赋值为 nil,那么就代表是当前可选类型的变量就为没有值的状态。这里有点绕,并不是说当前的变量为 nil,而是一种状态而已。换句话说,当给一个可选类型赋值为nil的时候,并不是将 nil给当前的变量,而是将当前的变量变成一个 没有值 的状态。

同时也要注意这里强调的是可选类型,没有说指针。所以可选类型可以是基本数据类型,也可以是所谓的指针。

接着上面的定义:

var a:Optional<Int>
var b:Int?
var c:Int!

以上的三个都是可选类型的变量。在定义可选类型的时候,不给赋值,那么当前的可选类型的变量就属于没有值的状态。那么问题来了,那他到底是什么值呢?

答案是 没有值 的状态,说明当前变量属于一个没有值的状态。

说了半天的可选类型,那么非可选类型的又是怎么样的呢?

var b:Int

上面这句代码,在 Swift 中是不能通过的。因为这是一个非可选类型的变量,非可选类型的变量,每时每刻都必需要保证有值。比如这样的:

image.png

接下来看一个变量的有值与没有值之间的转换:

// 定义一个可选类型的变量
// 当前的 e, 是没有值的状态
var e:Int?

// 当前的 e, 是有值的状态
e = 3

// 当前的 e, 变成了一个没有值的状态
e = nil

三、获取可选类型的值

3.1 获取可选类型的值(上)

可选类型,是一个单独的数据类型。对于赋值来说,与我们熟悉的赋值没有任何区别,是一个 Int 类型的值,直接给一个数字就可以了,其它类型的类似。但是取值,就有点不一样了。
看一下下面的打印结果:


image.png

可以看出,实际的值被一个 Optional 包起来了。再来看一下这个:

image.png

直接报错了,说明可选类型的是不能直接使用的。那应该如何去获取呢?
在上图的报错中, 就已经有提示了,正确的获取方式是:

print(e! + 3)

一般在 可选类型的后面加一个 ! 就可以了。但是这只是其中的一种情况,具体的放在后面介绍。在上面也介绍了,可选类型是一种独立的类型,只是每种可选类型肯定是对应着某种特定的数据类型。我们对可选类型的取值,主要的目的就是获取当前可选类型中的特定数据类型的值。

3.2 获取可选类型的值(下)

上面简单的介绍了。对于一个可选类型变量的取值,是需要做一些处理的,不能直接获取。接下来的问题是:

对于可选类型变量的取值,应该注意些什么呢?

image.png

说明,对于一个可选类型的变量来说,如果当前的变量为 没有值 的状态,还去获取值的话,这是不允许的,直接报错。

3.3 获取可选类型的值(终)

从上面的分析可以得出,获取可选类型的值,一定要保证当前可选类型变量处于有值的状态,否则直接报错。细心想想也对,尽然当前的变量的状态就是一个没有值的状态了,你还要去取值,这不是找死么?

那么问题又来了: 我们应该如何去获取可选类型的值呢? 关于这个问题,我们主要是围绕着 只会在有值的状态下,才去解包取值。

3.3.1 if 取值法
// if 取值法
if e != nil {
    print(e! + 3)
}

意思就是先判断 e 是否不为 nil, 如果不为 nil, 那么就强制解包取值。

3.3.2 绑定取值
// 绑定取值
if let e_value = e  {
    print(e_value + 3)
}

这种方式比第一种方式方便了很多,直接通过 if 判断当前的 e 是否有值,如果有值,则直接强制解包为 e_value, 如果没有值,那么当前的 if 条件不成立。

3.3.3 guard取值
// 函数
func hgFunc(e:Int?) {
    guard let e_guard_value = e else {
        print("e 当前没有值")
        return
    }
    print(e_guard_value)
}

函数 hgFunc 中的参数是一个可选类型,所以在使用的的时候可定需要做判断。但是这个 guardif 很相似,同时也还有很大的不同。仔细观察会发现,括号中执行的条件是 为 false 的情况下才会执行。还有一个更明显的特点是 e_guard_value 这个变量,在 e_guard_value的括号外面还能有效。如果使用 if 的话,还需要额外的声明一个变量。

3.3.4 双问号取值
// 如果 e 有值, 则获取 e 中的值
// 没有值, 则赋值为5
let e_value = e ?? 5

// 所以 e_value 值要么是 e 中的值
// 要么是 5
print(e_value)

这种方式也比较的直观,能很好的处理一些一定要保证能获取一个有效值的情况。

四、说在后面的话

是的,对于可选类型,我暂时就理解到这里了。在 Swift 开发中,使用得最多的即使可选类型的变量,所以理解好可选类型是很关键的一步。当然,主要是理解好,并在不同的场景使用好才是最关键的。

上一篇下一篇

猜你喜欢

热点阅读