「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」
枚举类型的创建
在Swift
语言中,通过enum
关键字来进行枚举
的创建,比如,我们可以创建一个花的枚举类型:
我们使用case
进行枚举类型
的定义,在上述代码中,我们每一个定义都使用了一个case
,我们也可以在一个case
中定义多个枚举值:
枚举值的使用
在使用时,和其他类型一样,我们可以在声明变量时将其类型指定为某个枚举类型,或者通过变量初始化的方式让编译器自动推断出变量的类型。
在Swift
中,如果已经确认变量是某一个枚举类型,那么在使用时,可以将枚举类型省略掉,直接使用点语法,如下:
我们通过两种方式定义了f1
和f2
两个变量,他们都是Flowers
的枚举类型,不同的是f1
是先声明变量,然后进行赋值,而f2
是直接给变量一个初始化的值,让编译器自动判断其类型,然后进行再次赋值;
需要注意的是,因为f2
在进行初始化时,必须告诉编译器他是哪一个枚举类型,所以不能省略枚举类型:
在实际开发中,枚举类型
经常与switch-case
结合使用来实现选择,如下:
需要注意的是,在
switch
需要穷尽枚举值,否则将会报错;
枚举的原始值
枚举
的原始值
特性可以将枚举值
与另一个数据类型
进行绑定,相关值
则可以为枚举值
关联一些其他数据;
原始值
在C
和OC
中,枚举时默认受整数
支持的,也就意味着在如下枚举中,A,B,C
分别默认为0,1,2
:
在Swift
中的枚举则更加灵活,并且不需要给枚举中的每一个成员都提供值,如果一个值原始值
要被提供给每一个枚举成员,那么这个值可以是字符串
,字符
或者浮点类型
等等;
如下,我们给枚举指定一个原始值类型:
我们给Flowers
指定为String
类型,并通过赋值
的方式来为枚举值
设置一个原始值
;
如果我们要指定的枚举的原始值类型
是Int
类型,那么可以只设置第一个枚举值的原始值
,其后边的的枚举值的原始值
会在第一个枚举值原始值的基础上记性依次递增,这属于隐式RawValue分配
,其建立在Swift的类型推断机制
上,如下代码:
我们可以通过枚举类型中的rawValue
属性来获取枚举的原始值
,我们看如下代码:
通过rawValue
属性我们获取到了枚举的原始值
,我们还发现,对于String
类型的枚举而言,系统给每一个枚举都默认了一个同名的原始值
;我们可以通过SIL
文件来分析一下:
我们在访问rawValue
的时候,其实是在访问其get
方法,我们通过下边代码来分析一下其过程:
生成SIL
文件之后,我们分析其调用:
在调用StringValue.rawValue.getter
方法时,实质是调用了apply %6(%5)
,%5
是StringValue.a!enumult
,而%6
对应方法的实现为:
将传入的值与StringValue
进行匹配,因为我们传入的StringValue.a!enumult
,所以会匹配上case #StringValue.a!enumult: bb1
,然后会执行bb1
对应的方法:
可以看到bb1
直接拿到了一个字符串常量a
,而一般常量是存储在MachO
文件中的cstring
中:
a
字符串是直接在cstring
表中通过地址找到的的,此过程可以通过汇编代码验证;
可失败初始化器
在SIL
中我们从enum
的定义在看到有一个可失败初始化器init?(rawValue: String)
,也就是我们可以通过此方法来构造一个枚举变量:
var aaa = StringValue.init(rawValue: "a")
复制代码
需要注意的是,通过原始值
进行枚举实例的构造时,是有可能构造失败的,因为我们传入的原始值
不一定会对应某一个枚举值
。因此该方法返回的是一个Optional
类型的可选值,如果构造失败,则返回nil
:
原始值的
rawValue
其实是存放在一片连续的内存空间,调用init(rawValue:)
的时候,其实是从一个连续的数组中查找对应的字符串