Swift 枚举中的关联值和原始值以及嵌套枚举

3,667 阅读2分钟

关联值

枚举的关联值使用如下:

enum HTTPResult {
    case success(code: Int)
    case failure(code: Int, description: String)
}

在 Swift 的枚举中,关联值是直接存储在枚举对象的内存中的。这个可以通过下面的打印得出:

print(MemoryLayout<HTTPResult>.size) // 25
print(MemoryLayout<HTTPResult>.stride) // 32

可以看到 HTTPResult 实际占用的内存为 25个字节,25 = 8(Int 占 8 个字节) + 16(String 占 16 个字节) + 1(用来区分是哪一个 case)。而因为存在系统对齐的原因,所以给它分配了 32 个字节。

总结起来就是,枚举占用的内存分为两个部分:1)区分 case 占用一个字节;2)所有 case 中取关联值占用内存最大的那个值用来存储关联值。比如上面的 success 关联值占 用 8 个字节,failure 关联值占用 24 个字节,则取最大值 24。

原始值

枚举的原始值使用如下:

enum Direction: Int {
    case east = 1, west, south, north
}

print(MemoryLayout<Direction>.size) // 1
print(MemoryLayout<Direction>.stride) // 1

虽然每个 case 都给赋予了 Int 类型原始值,但我们通过打印可以得知:Direction 的内存还是只占有 1 个字节,也就是说 Int 类型的原始值并没有放在 Direction 实例的内存中。

特殊情况

只有一个 case,且没有关联值

通过上面的例子可以看出,如果枚举没有关联值且有多个 case 的话,它会占用 1 个字节,用来区别是哪一个 case。那如果一个枚举只有 1 个 case,会占用多少内存呢?

enum HTTPResult {
    case success
}

print(MemoryLayout<HTTPResult>.size) // 0
print(MemoryLayout<HTTPResult>.stride) // 1

通过打印可以看出,虽然系统给它分配了 1 个字节的内存,但它并没有占用,原因就是只有 1 个 case,没必要再去占用内存去区分。

只有一个 case,且有关联值

enum HTTPResult {
    case success(code: Int)
}

print(MemoryLayout<HTTPResult>.size) // 8
print(MemoryLayout<HTTPResult>.stride) // 8

因为就是只有 1 个 case,也没必要再去占用内存去区分。所以系统只分配了 8 个字节去存储关联值。

嵌套枚举

在 Swift 中,枚举是可以嵌套的,用 indirect 关键字标识:

indirect enum Test {
    case first, second(t1: Test)
}