一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情。
枚举的大小
接下来我们来讨论一下枚举占用的内存大小,这里我们区分几种不同的情况,首先第一种就是 No-payload enums 。
///UInt8
/// 最多可存储256个case
enum Week {
case MONDAY
case TUEDAY
case WEDDAY
case THUDAY
case FRIDAY
case SATDAY
case SUNDAY
}
print(MemoryLayout<Week>.size)
打印结果是**1**字节。
可以看到这里我们测试出来的不管是 size 还是 stride 都是 1 ,这个地方我们也很好理解,当前的 enum 有几个 case ? 是不是 8 个啊,在 Swift 中进行枚举布局的时候一直是尝试使用最少的空间来存储 enum ,对于当前的 case 数量来说, UInt8能够表示 256 cases ,也就意味着如果一个默认枚举类型且没有关联值的 case 少于 256 ,当前枚举类型的大小都是 1 字节。
通过上面的打印我们可以直观的看到,当前变量 a , b , c这三个变量存储的内容分别 是 00, 01, 02 这和我们上面说的布局理解是一致的。
No-payload enums 的布局比较简单,我们也比较好理解,接下来我们来理解一下 Single- payload enums 的内存布局, 字面意思就是只有一个负载的 enum, 比如下面这个例子:
enum ZGEnum {
case test_one(Bool)
case test_two
case test_three
case test_four
}
print(MemoryLayout<ZGEnum>.size)
print(MemoryLayout<ZGEnum>.stride)
大家猜一下当前的这个案例, enum 在内存中的大小是多少?
1
1
如果我把当前的案例换一下,换成如下的案例,那么当前 enum 占用的大小又是多少?
enum ZGEnum {
case test_one(Int)
case test_two
case test_three
case test_four
}
print(MemoryLayout<ZGEnum>.size)
print(MemoryLayout<ZGEnum>.stride)
结果是
9
16
这里我们就产生了疑问了,为什么都是单个负载,但是当前占用的大小却不一致?
注意, Swift 中的 enum 中的 Single-payload enums 会使用负载类型中的额外空间来记录没有负载的 case 值。这句话该怎么理解?首先 **Bool 类型**是 **1**字节,也就是 UInt8 ,所以当前能表达 256 个 case的情况,对于 Bool类型来说,只需要使用低位的 0, 1 这两种情况,其 他剩余的空间就可以用来表示没有负载的 case 值。
enum ZGEnum {
case test_one(Bool)
case test_two
case test_three
case test_four
}
var a = ZGEnum.test_one(false)
var b = ZGEnum.test_one(true)
var c = ZGEnum.test_two
var d = ZGEnum.test_three
var f = ZGEnum.test_four
enum ZGEnum {
case test_one(Int)
case test_two
case test_three
case test_four
}
print(MemoryLayout<ZGEnum>.size)
print(MemoryLayout<ZGEnum>.stride)
var a = ZGEnum.test_one(10)
var b = ZGEnum.test_one(20)
var c = ZGEnum.test_two
var d = ZGEnum.test_three
var f = ZGEnum.test_four
对于 Int 类型的负载来说,其实系统是没有办法推算当前的负载所要使用的位数,也就意味着当前 Int 类型的负载是没有额外的剩余空间的,这个时候我们就需要额外开辟内存空间来去存储我们的 case 值,也就是 8 + 1 = 9 字节。