Swift中枚举的内存布局

枚举

枚举的基本用法

enum Direction {
    case north
    case south
    case east
    case west
}
let dir: Direction = .north

关联值(Associated Values)

enum Score {
    case points(Int)
    case grade(String)
}

let score: Score = .points(3)

原始值(Raw Values)

  • 枚举成员可以使用相同类型的默认值预先对应,这个默认值叫做:原始值
  • 原始值不占用枚举变量的内存
enum Grade: String {
    case perfect = "A"
    case great = "B"
    case good = "C"
    case bad = "D"
}

隐式原始值(Implicitly Assigned Raw Values)

  • 如果枚举的原始值类型是Int,String,Swift会自动分配原始值
enum Direction: String {
    case north = "north"
    case south = "south"
    case east = "east"
    case west = "west"
}

/// 等价于
enum Direction {
    case north
    case south
    case east
    case west
}

递归枚举(Recursive Enumeration)

indirect enum ArithExpr {
    case number(Int)
    case sum(ArithExpr, ArithExpr)
}
enum ArithExpr {
    case number(Int)
    indirect case sum(ArithExpr, ArithExpr)
}

MemoryLayout

  • MemoryLayout可以获取到数据类型占用的内存大小

基础枚举内存大小为

- 系统分配1个字节
- 实际用到1个字节
- 按1个字节对接

enum TestEnum1 {
    case test1
    case test2
    case test3
}

enum TestEnum2: Int {
    case test1
    case test2
    case test3
}

var test = TestEnum1.test3
print(Mems.ptr(ofVal: &test))
print(Mems.size(ofVal: &test))
let stride = MemoryLayout.stride // 1
let size = MemoryLayout.size // 1
let alignment = MemoryLayout.alignment // 1

关联值枚举内存大小为(TestEnum3为例)

- 分配的内存大小为32个字节
- 实际用到的字节为25个字节
- 以8个字节对齐
enum TestEnum3 {
   case test1(Float, Int, Int)
   case test2(Int, Int, Int)
   case test3(Int)
   case test4(Bool)
   case test5
}

// 01 00 00 00 00 00 00 00
// 02 00 00 00 00 00 00 00
// 03 00 00 00 00 00 00 00
// 01
// 分配了32个字节,但是只用到25个字节,前24个字节用来存储关联值,第25个字节用来存储成员值
var test = TestEnum3.test2(1, 2, 3)
// 01 00 00 00 00 00 00 00
// 02 00 00 00 00 00 00 00
// 03 00 00 00 00 00 00 00
// 00
test = .test1(1, 2, 3)
// 03 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 02
test = .test3(3)
// 01 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 03
test = .test4(true)

// 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 04
test = .test5

let stride = MemoryLayout.stride // 32
let size = MemoryLayout.size // 25
let alignment = MemoryLayout.alignment // 8

总结:

  • 1个字节存储成员值
  • N个字节存储关联值(N去最大case的关联值的个数),任何一个case的关联值共用这N个字节
  • 只有1个case的无关联值枚举内存为0
  • 单个case的关联值枚举内存关联值的内存大小 (因为就一个case,不需要存储值来区分)
  • 原始值不占用内存大小(为什么?因为可以这样写)
     var rawValue: Int {
         switch self {
         case .test1:
             return 0
         case .test2:
             return 1
         case .test3:
             return 2
         case .test4:
             return 3
         case .test5:
             return 4
         }
     }

你可能感兴趣的:(Swift中枚举的内存布局)