「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」
关联值
枚举的设计思路可以帮助我们将一些简单的同类数据进行整合,比如,我们需要表示一个模型,我们可以定义如下枚举:
我们枚举Shape,定义了圆形和矩形,但是这种枚举的定义只适合简单数据类型的定义,而不同的形状可能需要不同的参数。比如,圆形需要圆心和半径,矩形需要中心点和宽高来确定。
在Swift语言中,对枚举设置关联值就可以完成这样的需求。在定义枚举值的时候,我们可以设置参数列表,这个参数列表就称为枚举的关联值。比如如下代码:
对于
枚举变量来说,如果给定了关联值,那么其就没有了原始值;
在创建关联值枚举的时候,我们需要提供参数列表中所需要的参数。
关联值匹配
在switch-case结构中,匹配到枚举之后,可以通过参数捕获的方式来获取枚举的关联值,代码如下:
在上述代码中,写了两种参数捕获的方式,let直接在枚举前,或者let在关联值前;如果需要修改关联值,可以将let修改为var,如下:
枚举的大小
在内存中枚举是值类型,其存储在栈上;接下来我们来分析一下,枚举占用空间的大小;
没有关联值的枚举大小
我们先来看一个简单的枚举,打印其大小,代码如下:
结果打印其大小为1字节,这是因为对于没有指定类型的枚举TestValue来说,其默认是UInt8类型,刚好占用1字节;而由于UInt8最多存储256,所以当枚举超过256个的时候,将会升级为UInt16,之后UInt32,UInt64依次升级(正常开发过程中,我们的枚举也不可能有这么多);
枚举的隐式值已经硬编码进MachO文件中,我们只需要存储枚举值;
我们可以通过查看其内存数据来验证一下:
通过打印我们发现,a,b``c在内存中是连续存储的,并且其内存地址都相差1字节;
只有一个关联值的枚举大小
那么,如果我们的枚举有关联值,其大小是怎么计算的呢?我们看下边示例代码:
接下来,分别将Bool类型修改为Int类型进行打印:
结果打印为9,这是什么愿意呢?
在计算枚举类型大小时,系统会判断
关联值的类型是否有额外的空间来存储枚举值的大小;
以Bool为例,Bool占用1个字节,也就是8位,但是Bool类型实际占用的空间只是这8位中的1位,会多出来7位 ,也就是128个,我们的枚举并没有那么多,所以最终只有1字节就可以存储下枚举;
以Int为例,Int占用8个字节,也就是64位,没有多余的存储空间,需要额外的空间来存储其枚举值,所以最终是8+1=9个字节;但是需要注意的是,根据字节对齐原则,其步长此时为16;
关联值类型不同
我们前边计算的枚举,它的关联值类型都相同,如果枚举的关联值类型不同呢?如下代码所示:
在此枚举中,虽然都只是一个关联值,但是却又Bool``Int和String三种类型,这个时候我们需要比较三个关联值,找到占用空间最大的那个关联值类型,此处为String,占用16字节,所以最终大小为16 + 1 = 17;
有多个关联值的枚举大小
那么,如果我们的枚举中,有多个关联值呢?我们来看下边示例代码:
枚举中有三个Int和一个Bool,最终打印结果是25,这是因为,3个Int占用了24字节,Bool占用了1个字节中的1位,剩下的7位可以存放枚举值,所以最终结果是3 * 8 + 1 = 25;
如果我们将其中一个枚举中的关联值交换顺序呢?如下所示:
最终结果却变成了33,这是为什么呢?其大小的计算我们可以这么理解:
纵观所有的case,找出关联值最多的case,然后每一个case的关联值按照顺序逐个比较,找出占用空间最大的关联值:第一个关联值占用空间最大的为Int类型,是8字节,剩下的第二,第三,第四关联值依次如此比较,最终发现,占用空间最大的是4个Int,那么最终枚举大小为4 * 8 + 1 = 33;