In this article we explore the implementation of swift enumeration
Original value (RawValue)
Enumerated values
Let’s start by defining the following enumeration
enum Weekend: String {
case MON
case TUE
case WED
case THU
}
Copy the code
Weekend is a String enumeration whose RawValue we enter
var w = Weekend.MON.rawValue
print(w) // MON
Copy the code
The output is pretty much what we expect, with the string Mon.
SIL analysis
So let’s use SIL to analyze why RawValue is Mon,
swiftc -emit-sil main.swift | xcrun swift-demangle > ./main.sil && open main.sil
Copy the code
Sil file:
enum Weekend : String { case MON case TUE case WED case THU typealias RawValue = String init? (rawValue: String) var rawValue: String { get } // 1 } // Weekend.rawValue.getter sil hidden @main.Weekend.rawValue.getter : Swift.String : $@convention(method) (Weekend) -> @owned String { // %0 "self" // users: %2, %1 bb0(%0 : $Weekend): debug_value %0 : $Weekend, let, name "self", argno 1 // id: %1 // 2 switch_enum %0 : $Weekend, case #Weekend.MON! enumelt: bb1, case #Weekend.TUE! enumelt: bb2, case #Weekend.WED! enumelt: bb3, case #Weekend.THU! enumelt: bb4 // 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 @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 bb5(%8 : $String)Copy the code
- 1, we can see that
rawValue
Is agetter
Methods. - 2, through
switch_enum
To judge the enumerated values. bb1
: At the compiler, the compiler is generated"Mon"
String stored in MachO file__text
Segment, when matched toWhen the enumeration value is Mon, return "Mon"
.
Initialization method
In this case we can see that the Swift enumeration is done through init? (rawValue:) method. Let’s initialize the two enumerated variables separately
var mon = Weekend.init(rawValue: "MON")
var sat = Weekend.init(rawValue: "SAT")
print(mon) // Optional(LYSwift.Weekend.MON)
print(sat) // nil
Copy the code
Why does mon enumeration have a value and SAT enumeration is nil? , let’s look at its init method
// 1
sil hidden @main.Weekend.init(rawValue: Swift.String) -> main.Weekend? : $@convention(method) (@owned String, @thin Weekend.Type) -> Optional<Weekend> {
// %0 "rawValue" // users: %101, %95, %49, %3
// %1 "$metatype"
bb0(%0 : $String, %1 : $@thin Weekend.Type):
// 2
%2 = alloc_stack $Weekend, var, name "self" // users: %99, %91, %80, %69, %58, %102, %96
debug_value %0 : $String, let, name "rawValue", argno 1 // id: %3
%4 = integer_literal $Builtin.Word, 4 // 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: %50, %49
%8 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*StaticString // users: %17, %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
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
bb8: // Preds: bb7
%46 = struct $StaticString (%42 : $Builtin.Word, %41 : $Builtin.Word, %44 : $Builtin.Int8) // user: %47
store %46 to %39 : $*StaticString // id: %47
// function_ref _findStringSwitchCase(cases:string:)
%48 = function_ref @Swift._findStringSwitchCase(cases: [Swift.StaticString], string: Swift.String) -> Swift.Int : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // user: %49
%49 = apply %48(%7, %0) : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // users: %86, %75, %64, %53, %84, %73, %62, %51
release_value %7 : $Array<StaticString> // id: %50
debug_value %49 : $Int, let, name "$match" // id: %51
%52 = integer_literal $Builtin.Int64, 0 // user: %54
%53 = struct_extract %49 : $Int, #Int._value // user: %54
%54 = builtin "cmp_eq_Int64"(%52 : $Builtin.Int64, %53 : $Builtin.Int64) : $Builtin.Int1 // user: %55
cond_br %54, bb9, bb10
Copy the code
- 1, whose return value is
Optional<Weekend>
Type. - 2,
alloc_stack
: It is stored inStack space
On. - 3,
bb0,bb2...
: it will take all of its enumerated valuesRawValue: MON, TUE, WED and THU
And store it in an array. - 4,
bb8
Through:_findStringSwitchCase
Method that looks in an array for incomingRawValue
If not found, returnnil
. If found, the corresponding enumeration value is returned.
The associated values
enum Shape {
case circle(radious: Double)
case rectangle(width:Int, height: Int)
}
Copy the code
If an enumeration has an associated value, the enumeration has no original value.
Pattern matching
Match the original value
var mon = Weekend.init(rawValue: "MON")
switch mon {
case .MON:
print("MON")
case .TUE:
print("TUE")
default:
print("other")
}
Copy the code
Note here that all patterns need to be matched, and you can use default to match all other enumerated values.
Matching correlation value
Matching multiple cases
enum Shape {
case circle(radious: Double)
case rectangle(width:Int, height: Int)
}
var shape: Shape? = Shape.circle(radious: 10)
switch shape {
case .circle(let radious):
print(radious)
case .rectangle(let width, let height):
print("width:\(width), height: \(height)")
default:
print("other")
}
Copy the code
Match a case
var shape: Shape = Shape.circle(radious: 10)
if case let Shape.circle(radious) = shape {
print("\(radious)")
}
Copy the code
conclusion
Here we briefly summarize the RawValue of swift enumeration, initialization of enumeration, and pattern matching.