---页首---

Swift从入门到精通第三篇 - 枚举及内存布局

枚举及内存布局(学习笔记)

环境Xcode 11.0 beta4 swift 5.1

  • 枚举的基本用法

    enum Direction {
    	case north
    	case south
    	case east
    	case west
    }
    enum Direction {
    	case north, south, east, west
    }
    // 以上两种写法是等价
    var dir = Direction.west
    dir = Direction.east
    dir = .north
    print(dir) // north
    switch dir {
    case .north:
    	print("north")
    case .south:
    	print("south")
    case .east:
    	print("east")
    case .west:
    	print("west")
    }
    
  • 关联值(Associated Values)

    • 有时将枚举的成员值跟其他类型的值关联存储在一起会非常有用
    enum Score {
    	case points(Int)
    	case grade(Character)
    }
    var score = Score.points(96)
    score = .grade("A")
    switch score {
    case let .points(i):
    	print(i, "points")
    case let .grade(i):
    	print("grade", i);
    } // grade A
    
    enum Date {
    	case digit(year: Int, month: Int, day: Int)
    	case string(String)
    }
    var date = Date.digit(year: 2011, month: 10, day: 7)
    date = .string("2011-10-7")
    switch date {
    case .digit(let year, let month, var day):
    	print(year, month, day)
    case let .string(value):
    	print(value)
    }
    // year month day 可以用 `let` 或者 `var` 修饰
    
  • 原始值(Raw Values)

    • 枚举成员可以使用相同类型的默认值预先对应,这个默认值叫做原始值, 原始值不占用枚举变量的内存
    enum PokerSuit : Character {
    	case spade = "♠️"
    	case heart = "♥️"
    	case diamond = "♦️"
    	case club = "♣️"
    }
    var suit = PokerSuit.spade
    print(suit) // spade
    print(suit.rawValue) // ♠️
    print(PokerSuit.club.rawValue) // ♣️
    
  • 隐式原始值(Implicitly Assigned Raw Values)

    • 如果枚举的原始值类型是Int、 String, Swift会自动分配原始值
    enum Direction : String {
    	case north = "north"
    	case south = "south"
    	case east = "east"
    	case west = "west"
    }
    // 上面的枚举变量的原始值等价下面
    enum Direction : String {
    	case north, south, east, west
    }
    print(Direction.north) // north
    print(Direction.north.rawValue) // north
    enum Season : Int {
    	case spring, summer, autumn = 4, winter
    }
    print(Season.spring.rawValue) // 0
    print(Season.summer.rawValue) // 1
    print(Season.autumn.rawValue) // 4
    print(Season.winter.rawValue) // 5
    
  • 递归枚举(Recursive Enumeration)

    • 使用关键字 indirect, 可以用在 enum 前面,也可以用在枚举成员变量前面(case 前面)
    indirect enum ArithExpr {
    	case number(Int)
    	case sum(ArithExpr, ArithExpr)
    	case difference(ArithExpr, ArithExpr)
    }
    let five = ArithExpr.number(5)
    let four = ArithExpr.number(4)
    let two = ArithExpr.number(2)
    let sum = ArithExpr.sum(five, four)
    let diff = ArithExpr.difference(sum, two)
    func cal(_ expr: ArithExpr) -> Int {
    	switch expr {
    	case let .number(value):
    		return value
    	case let .sum(left, right):
    		return cal(left) + cal(right)
    	case let .difference(left, right)
    		return cal(left) - cal(right)
    	}
    }
    cal(difference) // 7
    
  • 枚举的内存布局

    enum TestEnum {
    case test0(Int, Int, Int)
    case test1(Int, Int)
    case test2(Int)
    case test3(Bool)
    case test4
    }
    print(MemoryLayout<TestEnum>.size)      // 25 实际用到的内存
    print(MemoryLayout<TestEnum>.stride)    // 32 申请分配的内存
    print(MemoryLayout<TestEnum>.alignment) // 8 内存对其参数
    // 一共申请32个字节,实际用到25个字节,实际要用到的内存要按关联值占用到的最大的内存,在本例中是test0最大,关联3个Int类型,在64位系统中每个Int占用8个字节
    // 因此要用24个字节,另外要一个字节即第25个字节用来标识枚举成员值,后面的7个字节用来内存补齐,以满足内存对齐
    // 小端模式
    // 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 (这一个字节标识枚举的成员值,0代表test0)
    // 00 00 00 00 00 00 00
    var t = TestEnum.test0(1, 2, 3)
    // 小端模式
    // 04 00 00 00 00 00 00 00
    // 04 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 01 (这一个字节标识枚举的成员值,1代表test1)
    // 00 00 00 00 00 00 00
    t = .test1(4, 5)
    // 小端模式
    // 06 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 02 (这一个字节标识枚举的成员值,2代表test2)
    // 00 00 00 00 00 00 00
    t = .test2(6)
    // 小端模式
    // 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 (这一个字节标识枚举的成员值,3代表test3)
    // 00 00 00 00 00 00 00
    t = .test3(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 (这一个字节标识枚举的成员值,4代表test4)
    // 00 00 00 00 00 00 00
    t = .test4
    
posted @ 2019-09-04 15:01  20190311  阅读(505)  评论(0编辑  收藏  举报
---页脚---