美文网首页
认识Swift系列4之枚举

认识Swift系列4之枚举

作者: Niuszeng | 来源:发表于2019-07-11 19:06 被阅读0次

    Swift中的枚举非常强大,但也会有也有点复杂,在不清楚其相关细节时,用球来总是没有那么得心应手,此文主要以代码呈现的方式秒速了swift枚举的一些特性

    1定义

    enum Direction1 {
        case up
        case down
        case left
        case right
    }
    
    enum Direction2 {
        case up, down, left, right
    }
    
    let d1 = Direction1.up
    switch d1 {
    case .up: print("d1 is up")
    case .down: print("d1 is down")
    default: print("d1 is none")
    }
    

    2.关联值

    enum Date {
        case digit(year: Int, month: Int, day: Int)
        case string(String)
    }
    
    let d1 = Date.digit(year: 2019, month: 7, day: 10)
    print(d1)
    let d2 = Date.string("2019-7-10")
    print(d2)
    
    enum Password {
        case number(Int, Int, Int, Int, Int, Int)
        case string(String)
    }
    

    3.原始值

    enum Grade: String {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad
    }
    
    // 如果不给原始值,会自动取名字字符串
    // 如果是字符类型Charater必须全部初始化
    let g: Grade = .good // g = good、g.rawValue = C
    print("g == \(g)")
    print("g rawValue == \(g.rawValue)")
    
    let g1: Grade = .bad // g = bad、g.rawValue = bad
    print("g1 == \(g1)")
    print("g1 rawValue == \(g1.rawValue)")
    
    
    // 隐式原始值,当后边不写是会自动有隐式原始值
    enum Grade1: String {
        case perfect
        case great
        case good
        case bad
    }
    /** 等价
     enum Grade1: String {
     case perfect = "perfect"
     case great = "great"
     case good = "good"
     case bad = "bad"
     }
     */
    enum Season: Int {
        case spring, summer, autumn, winter
    }
    /**
     enum Season: Int {
     case spring = 0
     case summer = 1
     case autumn = 2
     case winter = 3
     }
     */
    
    enum Season1: Int {
        case spring = 1, summer = 4, autumn, winter
    }
    /**
     enum Season: Int {
     case spring = 1
     case summer = 4
     case autumn = 5
     case winter = 6
     }
     */
    

    4.递归枚举

    • 枚举内部用到枚举本身,需要用 indirect 关键字声明
    • indirect 可修饰整个枚举、也可修饰部分枚举成员
    indirect enum AddEnum1 {
        case number(Int)
        case sum1(AddEnum1, AddEnum1)
        case sum2(AddEnum1, AddEnum1)
    }
    enum AddEnum2 {
        case number(Int)
        indirect case sum1(AddEnum2, AddEnum2)
        indirect case sum2(AddEnum2, AddEnum2)
    }
    
    func calculate(_ e: AddEnum1)->Int {
        switch e {
        case let .number(value):
            return value;
        case let .sum1(e1, e2):
            return calculate(e1) + calculate(e2);
        case let .sum2(e1, e2):
            return calculate(e1) + calculate(e2) + 10;
        }
    }
    
    let three = AddEnum1.number(3)
    let four = AddEnum1.number(4)
    let sum = AddEnum1.sum1(three, four)
    print("递归枚举:\(calculate(sum))")
    

    5.枚举内存探究

    • (1)拥有关联值的枚举【关联值内存+类型值内存】
    enum Date {
        case digit(year: Int, month: Int, day: Int) // 3*8 = 24 bytes
        case string(String) // 16 bytes
    }
    /** Date 内存
     digit: 需要24个字节存储关联值
     string: 需要16个字节存储关联值
     分类内存时,以最大成员值为基准,因此需要24个字节
     由于要区分类型digit和string,另需一个字节存储type
     因此实际使用 24+1 = 25,内存对其关系:24+8 = 32
     因此实际需要一个Date枚举变量需要占用 32个字节
     
     let d:Date = .digit(year: 3, month: 8, day: 10)
     0x00 00 00 00 00 00 00 03  // 前8个字节
     0x00 00 00 00 00 00 00 08  // 8个字节
     0x00 00 00 00 00 00 00 0a  // 8个字节
     0x00 00 00 00 00 00 00 00  // 最后8个字节(实际只使用一个),存储type
     */
    let d:Date = .digit(year: 3, month: 8, day: 10)
    print(MemoryLayout.stride(ofValue: d))  // 实际分配 32bytes
    print(MemoryLayout.size(ofValue: d))    // 实际使用 25bytes
    print(MemoryLayout.alignment(ofValue: d)) // 内存对其参数 8bytes
    
    • (2)由于没有关联值,只需要1个字节存储type即可 【类型值内存】
    enum Season {
        case spring, summer, autumn, winter
    }
    let s:Season = .spring
    print(MemoryLayout.stride(ofValue: s))  // 实际分配 1bytes
    print(MemoryLayout.size(ofValue: s))    // 实际使用 1bytes
    print(MemoryLayout.alignment(ofValue: s)) // 内存对其参数 1bytes
    
    • (3)拥有原始值【类型值内存】
    enum Seasonsss: String {
        case spring = "abc", summer = "bcd", autumn = "sss", winter
        var rawValue: String {
            switch self {
            case .spring:
                return "abc"
            case .summer:
                return "bcd"
            case .autumn:
                return "sss"
            case .winter:
                return "winter"
            }
        }
    }
    

    Note:注意,此处虽然有原始值,但实际上枚举变量的原始值并不占用枚举变量的内存空间
    枚举变量中任然只需1个字节存储type,即需要(0, 1, 2, ...)
    不论有无原始值、关联值都是如此 type:(0, 1, 2, ...)
    关联值会占用枚举变量的内存,而原始值则不占用枚举变量的内存
    事实上,枚举变量的原始值实现方式与类和结构体重计算属性相同,即方法实现

    
    enum Season1: String {
        case spring, summer, autumn, winter
    }
    let s2:Season1 = .spring
    print(MemoryLayout.stride(ofValue: s2))  // 实际分配 1bytes
    print(MemoryLayout.size(ofValue: s2))    // 实际使用 1bytes
    print(MemoryLayout.alignment(ofValue: s2)) // 内存对其参数 1bytes
    print(s2.rawValue)
    
     enum Season: Int {
     case spring = 20
     case summer = 40
     case autumn
     case winter
     }
    

    Note:类型值
    注意:虽然后边写了 20 和 40,但是实际上枚举变量并不会存储该值,在内存中依然为
    0,1,2,3,而20, 40则会使用rawValue计算属性(方法)实现

    枚举中通常只使用一个字节存储类型值,,0-255,当超过255时,再使用枚举说明设计上有问题,应该更改方案

    相关文章

      网友评论

          本文标题:认识Swift系列4之枚举

          本文链接:https://www.haomeiwen.com/subject/wthjkctx.html