美文网首页
swift--枚举

swift--枚举

作者: Mjs | 来源:发表于2020-12-21 15:47 被阅读0次

    C语言枚举

    enum 枚举名 { 
     枚举值1, 
     枚举值2, 
     ……};
    

    一周七天可以写成

    enum week 
     { 
       MON, TUE, WED, THU, FRI, SAT, SUN 
     };
    

    第⼀个枚举成员的默认值为整型的 0,后⾯的枚举值依次类推,如果我们想更改,只需要这样操作

    enum week 
     { 
       MON = 1, TUE, WED, THU, FRI, SAT, SUN 
     };
    

    那如何定义⼀个枚举变量

    
    enum week 
     { 
       MON = 1, TUE, WED, THU, FRI, SAT, SUN 
     } week;
    //可以省略声明的枚举
    enum week 
     { 
       MON = 1, TUE, WED, THU, FRI, SAT, SUN 
     } week;
    

    Swift 枚举写法

    enum week{
        case MONDAY
        case TUEDAY
        case WEDDAY
        case THUDAY
        case FRIDAY
        case SATDAY
        case SUNDAY
    }
    

    上述代码也可以直接⼀个 case ,然后⽤逗号隔开

    enum week{
        case MONDAY, TUEDAY, WEDDAY, THUDAY, FRIDAY, SATDAY, SUNDAY
    }
    

    枚举值默认是整形,也以表达为String

    enum week: String
    {
        case MON = "MON"
        case TUE = "TUE"
        case WED = "WED"
        case THU = "THU"
        case FRI = "FRI"
        case SAT = "SAT"
        case SUN = "SUN"
    }
    

    我们赋值的字符串叫做原始值(RawValue),,如果我们不想写后⾯的字符串,这个时候我们就 可以使⽤ 隐⼠ RawValue 分配

    enum week: Int {  case mon, tue, wed, thu, fri = 10, sat, sun  }
    print(week.fri.rawValue)
    ···········
    10
    
    
    enum week: String {  case MON, TUE, WED, THU, FRI , SAT, SUN  }
    print(week.FRI.rawValue)
    ···········
    FRI
    

    当改成String型之后,打印的值就变成了当前枚举值了。
    通过swiftc -emit-sil main.swift | xcrun swift-demangle > ./main.sil && open main.sil查看sil代码

    enum week : String {
      case MON, TUE, WED, THU, FRI, SAT, SUN
      typealias RawValue = String
      init?(rawValue: String)
      var rawValue: String { get }
    }
    
    
    // main
    sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
    bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
      alloc_global @main.w : Swift.String                     // id: %2
      %3 = global_addr @main.w : Swift.String : $*String      // user: %8
      %4 = metatype $@thin week.Type
      %5 = enum $week, #week.MON!enumelt              // user: %7
      // function_ref week.rawValue.getter
      %6 = function_ref @main.week.rawValue.getter : Swift.String : $@convention(method) (week) -> @owned String // user: %7
      %7 = apply %6(%5) : $@convention(method) (week) -> @owned String // user: %8
      store %7 to %3 : $*String                       // id: %8
      %9 = integer_literal $Builtin.Int32, 0          // user: %10
      %10 = struct $Int32 (%9 : $Builtin.Int32)       // user: %11
      return %10 : $Int32                             // id: %11
    } // end sil function 'main'
    

    %6调用了get方法,7%将%5也就是枚举值MON传参进去

    
    // week.rawValue.getter
    sil hidden @main.week.rawValue.getter : Swift.String : $@convention(method) (week) -> @owned String {
    // %0                                             // users: %2, %1
    bb0(%0 : $week):
    //声明一个变量self,等于参数week
      debug_value %0 : $week, let, name "self", argno 1 // id: %1
    //匹配枚举值,跳转到对应的分支
      switch_enum %0 : $week, case #week.MON!enumelt: bb1, case #week.TUE!enumelt: bb2, case #week.WED!enumelt: bb3, case #week.THU!enumelt: bb4, case #week.FRI!enumelt: bb5, case #week.SAT!enumelt: bb6, case #week.SUN!enumelt: bb7 // id: %2
    //创建String,跳转bb8
    bb1:                                              // Preds: bb0
      %3 = string_literal utf8 "MON"                  // user: %8
      %4 = integer_literal $Builtin.Word, 3           // user: %8
      %5 = integer_literal $Builtin.Int1, -1          // user: %8
      %6 = metatype $@thin String.Type                // user: %8
      // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
      %7 = function_ref @Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %8
      %8 = apply %7(%3, %4, %5, %6) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %9
      br bb8(%8 : $String)                            // id: %9
    ...
    //返回
    // %52                                            // user: %53
    bb8(%52 : $String):                               // Preds: bb7 bb6 bb5 bb4 bb3 bb2 bb1
      return %52 : $String                            // id: %53
    } // end sil function 'main.week.rawValue.getter : Swift.String'
    
    

    case 和 rawValue

    print(week.MON)
    print(week.MON.rawValue)
    

    虽然打印的都是MON,但是一个是枚举类型,一个是字符串类型

    枚举的init

    通过sil文件查看init方法

    
    // week.init(rawValue:)
    sil hidden @main.week.init(rawValue: Swift.String) -> main.week? : $@convention(method) (@owned String, @thin week.Type) -> Optional<week> {
    // %0                                             // users: %164, %158, %79, %3
    bb0(%0 : $String, %1 : $@thin week.Type):
      %2 = alloc_stack $week, var, name "self"        // users: %162, %154, %143, %132, %121, %110, %99, %88, %165, %159
      debug_value %0 : $String, let, name "rawValue", argno 1 // id: %3
      %4 = integer_literal $Builtin.Word, 7           // user: %6
      // function_ref _allocateUninitializedArray<A>(_:)
      %5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
      %6 = apply %5<StaticString>(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
    //构建元组,存放字符串数组和指针地址
      %7 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 0 // users: %80, %79
      %8 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 1 // user: %9
      %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*StaticString // users: %17, %69, %59, %49, %39, %29, %19
      %10 = string_literal utf8 "MON"                 // user: %12
      %11 = integer_literal $Builtin.Word, 3          // user: %16
      %12 = builtin "ptrtoint_Word"(%10 : $Builtin.RawPointer) : $Builtin.Word // user: %16
      br bb1                                          // id: %13
    
    bb1:                                              // Preds: bb0
      %14 = integer_literal $Builtin.Int8, 2          // user: %16
      br bb2                                          // id: %15
    
    bb2:                                              // Preds: bb1
      %16 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %14 : $Builtin.Int8) // user: %17
      store %16 to %9 : $*StaticString                // id: %17
      %18 = integer_literal $Builtin.Word, 1          // user: %19
      %19 = index_addr %9 : $*StaticString, %18 : $Builtin.Word // user: %27
      %20 = string_literal utf8 "TUE"                 // user: %22
      %21 = integer_literal $Builtin.Word, 3          // user: %26
      %22 = builtin "ptrtoint_Word"(%20 : $Builtin.RawPointer) : $Builtin.Word // user: %26
      br bb3                                          // id: %23
    
    
    //通过方法来进行匹配
    bb14:                                             // Preds: bb13
      %76 = struct $StaticString (%72 : $Builtin.Word, %71 : $Builtin.Word, %74 : $Builtin.Int8) // user: %77
      store %76 to %69 : $*StaticString               // id: %77
      // function_ref _findStringSwitchCase(cases:string:)
      %78 = function_ref @Swift._findStringSwitchCase(cases: [Swift.StaticString], string: Swift.String) -> Swift.Int : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // user: %79
      %79 = apply %78(%7, %0) : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // users: %149, %138, %127, %116, %105, %94, %83, %147, %136, %125, %114, %103, %92, %81
      release_value %7 : $Array<StaticString>         // id: %80
      debug_value %79 : $Int, let, name "$match"      // id: %81
      %82 = integer_literal $Builtin.Int64, 0         // user: %84
      %83 = struct_extract %79 : $Int, #Int._value    // user: %84
      %84 = builtin "cmp_eq_Int64"(%82 : $Builtin.Int64, %83 : $Builtin.Int64) : $Builtin.Int1 // user: %85
      cond_br %84, bb15, bb16  
    
    
    //如果成功,返回
    bb15:                                             // Preds: bb14
      %86 = metatype $@thin week.Type
      %87 = enum $week, #week.MON!enumelt             // user: %89
      %88 = begin_access [modify] [static] %2 : $*week // users: %89, %90
      store %87 to %88 : $*week                       // id: %89
      end_access %88 : $*week                         // id: %90
      br bb29                                         // id: %91
    //不成功继续匹配
    bb16:                                             // Preds: bb14
      debug_value %79 : $Int, let, name "$match"      // id: %92
      %93 = integer_literal $Builtin.Int64, 1         // user: %95
      %94 = struct_extract %79 : $Int, #Int._value    // user: %95
      %95 = builtin "cmp_eq_Int64"(%93 : $Builtin.Int64, %94 : $Builtin.Int64) : $Builtin.Int1 // user: %96
      cond_br %95, bb17, bb18                         // id: %96
    
    
    
    bb29:                                             // Preds: bb27 bb25 bb23 bb21 bb19 bb17 bb15
      %162 = load %2 : $*week                         // user: %163
    //返回的是可选类型,如果没有就是nil
      %163 = enum $Optional<week>, #Optional.some!enumelt.1, %162 : $week // user: %166
      release_value %0 : $String                      // id: %164
      dealloc_stack %2 : $*week                       // id: %165
      br bb30(%163 : $Optional<week>)  
    
    
    // %167                                           // user: %168
    bb30(%167 : $Optional<week>):                     // Preds: bb29 bb28
      return %167 : $Optional<week>                   // id: %168
    } // end sil function 'main.week.init(rawValue: Swift.String) -> main.week?'
    
    

    枚举的遍历

    enum week: String {  case MON, TUE, WED, THU, FRI , SAT, SUN  }
    
    extension week: CaseIterable{}
    var allCase = week.allCases
    for c in allCase {
        print(c)
    }
    

    只要实现了CaseIterable协议就可以。

    关联值

    如果我们想⽤枚举表达更复杂的信息,⽽不仅仅是⼀个 RawValue 这么简单,这个时候我们就可以使⽤ Associated Value,当声明了关联值后,就无法使用initRawValue

    enum Shape{
        case circle(radious: Double)
        case rectangle(width: Int, height: Int)
    }
    
    var circle = Shape.circle(radious: 10.0)
    circle = Shape.circle(radious: 20.0)
    switch circle{
    case let .circle(radious):
        print(radious)
    case .rectangle(let width, var height):
        height += 10
        print(width,height)
    }
    //也可以单独取出来用
    if case let Shape.circle(radious) = circle{
        print(radious)
    }
    

    当我们只关注不同枚举值的相同关联值

    enum Shape{
        case rectangle(width: Int, height: Int)
        case squar(width1: Int, height1: Int)
    }
    var circle = Shape.rectangle(width: 30, height: 40)
    switch circle{
    case let .rectangle(10, x), let .squar(width1: 10, height1: x):
        print(x)
    default:
        print("nil")
    }
    

    注意,前后变量要一一对应。不关注的也以用_来省略

    枚举的嵌套

    枚举中含有枚举
     enum CombineDirect{
        enum BaseDirect{
            case up
            case down
            case left
            case right
        }
        case leftUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
        case rightUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
        case leftDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
        case rightDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
    }
    let combind = CombineDirect.leftDown(combineElement1: .left, combineElement2: .down)
    
    结构体中包含枚举
    struct Skill{
        enum KeyType{
            case up
            case down
            case left
            case right
        }
        let key: KeyType
        func launchSkill(){
            switch key {
            case .left,.right:
                print("left, right")
            case .down,.up:
                print("up, down")
            }
        }
    }
    

    枚举中包含属性

    enum 中能包含计算属性,类型属性。不能包含存储属性

     enum Shape{
        case circle(radious: Double)
        case rectangle(width: Int, height: Int)
    //    var radious: Double
        static var height = 20.0
        var width: Double{
            get{
                return 10.0
            }
        }
    }
    

    枚举中包含方法

    enum week: Int {
        case MON, TUE, WED, THU, FRI , SAT, SUN
        
        mutating func nextDay(){
            if self == .SUN{
                self = week(rawValue: 0)!
            }else{
                self = week(rawValue: self.rawValue + 1)!
            }
        }
    }
    

    枚举的大小

    枚举的大小取决于枚举值,默认是UInt8大小,也就是一字节,超过UInt8容量就会升级为UInt16,也就是二字节,以此类推。
    存在关联值,取决最大case的大小

    
     enum Shape{
        case circle(radious: Double)
        case rectangle(width: Int)
    }
    
    print(MemoryLayout<Shape>.stride)
    print(MemoryLayout<Shape>.size)
    ·····
    16
    9
    

    Double占8字节,加上case的1字节,就是9字节,根据字节对齐,所以步长是16。

    indirect

    enum List<T>{
        case end
        indirect case node(T, next: List<T>)
    }
    
    print(MemoryLayout<List<String>>.size)
    print(MemoryLayout<List<String>>.stride)
    ·············
    8
    8
    

    打印添加了indirect的枚举大小为8字节

    var node = List<Int>.node(10, next: List<Int>.end)
    ·················
    (lldb) p withUnsafePointer(to: &node, {$0})
    (UnsafePointer<swiftTest.List<Int>>) $R6 = 0x0000000100003068
    (lldb) x/4g 0x0000000100003068
    0x100003068: 0x0000000100419fd0 0x00007fff98c81218
    0x100003078: 0x00007fff98c81218 0x00000001007824d0
    (lldb) x/4g 0x0000000100419fd0
    0x100419fd0: 0x0000000100002030 0x0000000000000002
    0x100419fe0: 0x000000000000000a 0x0000000000000000
    

    通过打印地址,发现把声明了indirect关键字的值放在了堆空间上。
    查看sil

    // main
    sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
    bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
      alloc_global @main.node : main.List<Swift.Int>        // id: %2
      %3 = global_addr @main.node : main.List<Swift.Int> : $*List<Int> // user: %16
      %4 = metatype $@thin List<Int>.Type
      %5 = integer_literal $Builtin.Int64, 10         // user: %6
      %6 = struct $Int (%5 : $Builtin.Int64)          // user: %13
      %7 = metatype $@thin List<Int>.Type
      %8 = enum $List<Int>, #List.end!enumelt         // user: %14
      %9 = alloc_box $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int> // users: %15, %10
      %10 = project_box %9 : $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int>, 0 // users: %12, %11
      %11 = tuple_element_addr %10 : $*(Int, next: List<Int>), 0 // user: %13
      %12 = tuple_element_addr %10 : $*(Int, next: List<Int>), 1 // user: %14
      store %6 to %11 : $*Int                         // id: %13
      store %8 to %12 : $*List<Int>                   // id: %14
      %15 = enum $List<Int>, #List.node!enumelt.1, %9 : $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int> // user: %16
      store %15 to %3 : $*List<Int>                   // id: %16
      %17 = integer_literal $Builtin.Int32, 0         // user: %18
      %18 = struct $Int32 (%17 : $Builtin.Int32)      // user: %19
      return %18 : $Int32                             // id: %19
    } // end sil function 'main'
    

    通过官方文档可以查看alloc_box的解释

    Allocates a reference-counted @box on the heap large enough to hold a value of type T, along with a retain count and any other metadata required by the runtime. The result of the instruction is the reference-counted @box reference that owns the box. The project_box instruction is used to retrieve the address of the value inside the box.
    在堆上分配一个引用计数的@box,其大小足以容纳类型T的值,以及retain计数和运行时所需的任何其他元数据。该指令的结果是引用计数的@box引用,该引用拥有该框。project_box指令用于检索框内值的地址。

    OC-Swift混编

    我们在Swift的枚举前加上@objc就可以了

    @objc enum WEEK: Int {
        case MON, TUE
    }
    

    编译一下,我们就可以在.h文件中查看


    查看转译文件.png
    typedef SWIFT_ENUM(NSInteger, WEEK, closed) {
      WEEKMON = 0,
      WEEKTUE = 1,
    };
    

    OC仅能使用声明为Int类型的。

    NS_ENUM
    **********OC**********
    NS_ENUM(NSInteger, OCENUM){
        Value1,
        Value2
    };
    
    
    **********SWIFT**********
    public var OCENUM: OCENUM
    
    public enum OCENUM : Int {
    
        
        case Value1 = 0
    
        case Value2 = 1
    }
    
    typedef enum

    如果用typedef enum来声明,就会编译成结构体

    **********OC**********
    typedef enum {
        Num1,
        Num2
    } OCNum;
    **********SWIFT**********
    public struct OCNum : Equatable, RawRepresentable {
    
        public init(_ rawValue: UInt32)
    
        public init(rawValue: UInt32)
    
        public var rawValue: UInt32
    }
    
    typedef NS_ENUM
    **********OC**********
    typedef NS_ENUM(NSInteger, CEnum) {
        CEnumInvalid = 0,
        CEnumA = 1,
        CEnumB,
        CEnumC
    };
    **********SWIFT**********
    public enum CEnum : Int {
    
        
        case invalid = 0
    
        case A = 1
    
        case B = 2
    
        case C = 3
    }
    

    相关文章

      网友评论

          本文标题:swift--枚举

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