Swift枚举

2020-12-24  本文已影响0人  浪的出名

C语言的枚举

enum 枚举名 { 
    枚举值1,
    枚举值2,
    ......
 };
enum Week {
    MON,TUS,WED,THU,FRI,SAT,SUN
};
enum Week {
    MON=3,TUS,WED,THU=9,FRI,SAT,SUN
};
// 这个枚举对应的值就是3,4,5,9,10,11,12

Swift的枚举

Swift枚举的使用

enum Week {
    case MON
    case TUS
    case WED
    case THU
    case FRI
    case SAT
    case SUN
}
// 也可以直接一个case,用逗号隔开
enum Week {
    case MON,TUS,WED,THU,FRI,SAT,SUN
}
enum Week : String {
    case MON = "MON"
    case TUS = "TUS"
    case WED = "WED"
    case THU = "THU"
    case FRI = "FRI"
    case SAT = "SAT"
    case SUN = "SUN"
}
enum Week : String {
  case MON
  case TUS
  case WED
  case THU
  case FRI
  case SAT
  case SUN
  typealias RawValue = String
  init?(rawValue: String)
  var rawValue: String { get }
}
print(Week(rawValue: "MON"))
print(Week(rawValue: "hello"))

// 打印结果  
Optional(SwiftEnumerate.Week.MON)
nil
// Week.init(rawValue:)
sil hidden @$s4main4WeekO8rawValueACSgSS_tcfC : $@convention(method) (@owned String, @thin Week.Type) -> Optional<Week> {
// %0 "rawValue"                                  // users: %164, %158, %79, %3
// %1 "$metatype"
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 @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@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 它的长度是3,我们在内存中分配的大小
  %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 获取当前数组中的值的地址,返回相对于首地址的第(%18)个元素的地址
  %20 = string_literal utf8 "TUS"                 // 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 @$ss21_findStringSwitchCase5cases6stringSiSays06StaticB0VG_SStF : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // user: %79 遍历之前创建的数组匹配就返回对应的index
  %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  循环比较当前的返回值和index,根据结果往下跳转不同的分支
  cond_br %84, bb15, bb16                         // id: %85
  
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
......
// 遍历完全部枚举值都没有找到,就会返回一个none
bb28:                                             // Preds: bb26
  release_value %0 : $String                      // id: %158
  dealloc_stack %2 : $*Week                       // id: %159
  %160 = enum $Optional<Week>, #Optional.none!enumelt // user: %161
  br bb30(%160 : $Optional<Week>)                 // id: %161
// 匹配成功就创建一个可选项返回
bb29:                                             // Preds: bb27 bb25 bb23 bb21 bb19 bb17 bb15
  %162 = load %2 : $*Week                         // user: %163
  %163 = enum $Optional<Week>, #Optional.some!enumelt, %162 : $Week // user: %166
  release_value %0 : $String                      // id: %164
  dealloc_stack %2 : $*Week                       // id: %165
  br bb30(%163 : $Optional<Week>)                 // id: %166

// %167                                           // user: %168
bb30(%167 : $Optional<Week>):                     // Preds: bb29 bb28
  return %167 : $Optional<Week>                   // id: %168
} // end sil function '$s4main4WeekO8rawValueACSgSS_tcfC'
/// The compiler intrinsic which is called to lookup a string in a table
/// of static string case values.
@_semantics("findStringSwitchCase")
public // COMPILER_INTRINSIC
func _findStringSwitchCase(
  cases: [StaticString],
  string: String) -> Int {

  for (idx, s) in cases.enumerated() {
    if String(_builtinStringLiteral: s.utf8Start._rawValue,
              utf8CodeUnitCount: s._utf8CodeUnitCount,
              isASCII: s.isASCII._value) == string {
      return idx
    }
  }
  return -1
}
// main 这里调用Week.rawValue.getter,返回一个字符串
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$s4main1aSSvp                     // id: %2
  %3 = global_addr @$s4main1aSSvp : $*String      // user: %8
  %4 = metatype $@thin Week.Type
  %5 = enum $Week, #Week.MON!enumelt              // user: %7 创建一个枚举值 MON
  // function_ref Week.rawValue.getter
  %6 = function_ref @$s4main4WeekO8rawValueSSvg : $@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'

// Week.rawValue.getter
sil hidden @$s4main4WeekO8rawValueSSvg : $@convention(method) (Week) -> @owned String {
// %0 "self"                                      // users: %2, %1
bb0(%0 : $Week):
  debug_value %0 : $Week, let, name "self", argno 1 // id: %1
  switch_enum %0 : $Week, case #Week.MON!enumelt: bb1, case #Week.TUS!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
// 匹配枚举值,构建字符串返回
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 @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@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
  ...... //省略掉其他case的判断,只判断为MON的时候
// %52                                            // user: %53
bb8(%52 : $String):                               // Preds: bb7 bb6 bb5 bb4 bb3 bb2 bb1
  return %52 : $String                            // id: %53
} // end sil function '$s4main4WeekO8rawValueSSvg'

这里需要注意的一点就是枚举值和RawValue是两个不同的东⻄,我们没有办法把一个枚举值分配一个String的变量,即使这个enumString类型的

关联值

enum Shape {
    case circle(radious:Double)
    case rectangle(width:Double,height:Double)
}
enum Shape {
    case circle(radious:Double)
    case rectangle(width:Double,height:Double)
    
}

var circle = Shape.circle(radious: 10.0)
var rectangle = Shape.rectangle(width: 15.0, height: 18.0)

枚举的其他用法

模式匹配

enum Shape {
    case circle(radious:Double)
    case rectangle(width:Double,height:Double)
    
}

var circle = Shape.circle(radious: 10.0)
var rectangle = Shape.rectangle(width: 15.0, height: 18.0)

switch circle {
    case let .circle(radious): print("circle radious\(radious)")
    case let .rectangle(width, height) : print("rectangle width:\(width),height:\(height)")
}
switch rectangle {
    case .circle(let radious): print("circle radious\(radious)")
    case .rectangle(let width,let height) : print("rectangle width:\(width),height:\(height)")
}
if case let Shape.circle(radious) = circle {
    print(radious)
}
enum Shape{ 
    case circle(radious: Double, diameter: Double) 
    case rectangle(width: Double, height: Double) 
    case square(width: Double, width: Double) 
}
let shape = Shape.circle(radious: 10.0, diameter: 20.0) 
switch shape {
    case let .circle(x, 20.0), let .square(x, 20.0): 
        print(x) 
    default: 
        break 
} 
switch shape {
    case let .circle(_, x), let .square(x, _):
        print(x) 
    default:
        break
}

switch shape {
    case let .circle(x, y), let .rectangle(y, x):
        print("x=\(x),y=\(y)") 
    default:
        break
}

枚举的嵌套

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)
}

结构体中的嵌套

struct Skill {
    enum KeyType {
        case up
        case down
        case left
        case right
    }
    
    let key : KeyType
}

枚举中包含属性和方法

enum Week : Int {
    case MON
    case TUS
    case WED
    case THU
    case FRI
    case SAT
    case SUN
    
    mutating func nextDay() {
        if self == .SUN {
            self = Week(rawValue: 1)!
        }else{
            self = Week(rawValue: 1+self.rawValue)!
        }
    }
    static func doSomething() {
        print("111\(self.init(rawValue: 1))")
    }
    
}

枚举的大小

enum noMean {
    case a
}

print(MemoryLayout<noMean>.size)
print(MemoryLayout<noMean>.stride)

// 打印结果为:0 1
enum noMean {
    case a
    case b
}

print(MemoryLayout<noMean>.size)
print(MemoryLayout<noMean>.stride)

// 打印结果为:1 1

// 修改rawValue的类型 打印结果不变
enum noMean : String {
    case a
    case b
}
// 打印结果为:1 1
enum Shape{
    case circle(radious: Double)
}
print(MemoryLayout<Shape>.size)
print(MemoryLayout<Shape>.stride)
// 打印结果为 8,8

enum Shape{
    case circle(radious: Double)
    case rectangle(width: Double, height: Double)
}
print(MemoryLayout<Shape>.size)
print(MemoryLayout<Shape>.stride)
// 打印结果为17,24
需要注意的一点是,由于字节对齐的原因,有时候`case`的1字节会被编译器优化加到前面的位置上,它的大小不会再+1

indirect关键字

indirect enum List<T> {
    case end
    case node(T, next : List<T>)
}
或
enum List<T> {
    case end
    indirect case node(T, next : List<T>)
}

You indicate that an enumeration case is recursive by writing indi rect before it, which tells the compiler to insert the necessary l ayer of indirection.

上一篇 下一篇

猜你喜欢

热点阅读