C language enumeration
- C language enumeration writing method
Enum Enum name {Enumeration value 1, enumeration value 2,...... };Copy the code
- We represent the seven days of the week by enumeration
enum Week {
MON,TUS,WED,THU,FRI,SAT,SUN
};
Copy the code
- In C, the default value of the first member of an enumeration is 0, and the subsequent enumeration value can be analogized, or the corresponding value can be specified directly, and the enumeration value after it is still incremented
enum Week { MON=3,TUS,WED,THU=9,FRI,SAT,SUN }; The values of this enumeration are 3,4,5,9,10,11,12Copy the code
Swift enumerated
Use of the Swift enumeration
- Implement this enumeration as well, written as follows
Enum Week {case MON case TUS case WED case THU case FRI case SAT case SUN} Use commas enum Week {TUS case MON, WED, THU, FRI, SAT, SUN}Copy the code
- This is an enumeration of integers, the same as in C,
Swift
Can also be expressed by enumerationString
enum Week : String {
case MON = "MON"
case TUS = "TUS"
case WED = "WED"
case THU = "THU"
case FRI = "FRI"
case SAT = "SAT"
case SUN = "SUN"
}
Copy the code
=
On the right isSwift
In theRawValue
If we don’t write the following string, it will defaultImplicit RawValue allocation
, or you can specify members of the enumeration individuallyRawValue
- Looking at the SIL file, you can see that one is automatically generated
init? (rawValue:)
Method, and oneget
methods
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 } }Copy the code
- Let’s see
init? (rawValue:)
When is the function called, observed by the symbolic breakpoint
- Run discovery:
Week.MON.rawValue
It doesn’t triggerinit
Function, only callsWeek(rawValue: "MON")
Will enter the symbol breakpoint, and then print the following code
Print (Week(rawValue: "MON")) print(Week(rawValue: "hello")) // Print result Optional(SwiftEnumerate.week.mon) nilCopy the code
- View the SIL file
init
Method, we will first put the enumeration values into an array, and then pass_findStringSwitchCase
Method matches the string passed in and returns one if a match is foundindex
If no match is found, return one- 1
If there is a match, the enumeration value is retrieved and returned as an optional value. If there is no match, the returned value is nil, so the return value is optional.
// 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 > (_) creates A tuple, there are enumerated values array, % 5 = function_ref @ $ss27_allocateUninitializedArrayySayxG_BptBwlF and Pointers: $@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 creates a string %11 = integer_literal $builtin. Word, 3 // user: %16 Its length is 3, the size we allocated in memory %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: %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: 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: Cond_br %84, bb15, bb16 // id: % 85bb15: // 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 ...... 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 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'Copy the code
Swift
In the source_findStringSwitchCase
The implementation of the
/// 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
}
Copy the code
- Now, how do you get it
rawValue
the
// main calls week.rawValue. getter to return the string 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 / / create an enumerated values function_ref Week. RawValue. 6 = function_ref getter % @ $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 // Match enumerations, build string returns 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 ...... // user: %53 bb8(%52: $String): // Preds: bb7 bb6 bb5 bb4 bb3 bb2 bb1 return %52: $String // id: %53 } // end sil function '$s4main4WeekO8rawValueSSvg'Copy the code
- In this case the enumerated values are string constants and should be stored in a Mach-O file
__TEXT,__cstring
As you can see, currently we specifyenum
theRawValue
forString
After that, the system automatically creates a contiguous memory space to hold the current by defaultcase
The corresponding string.
One thing to note here is that enumerations and rawValues are two different things. There is no way to assign a String variable to an enumeration, even if the enum is of type String
The associated values
- in
Swift
In, we can express complex information through enumeration values, that is, correlation values, through enumeration to express a shape, circle, rectangle, radius, rectangle width, height, this is very useful
enum Shape {
case circle(radious:Double)
case rectangle(width:Double,height:Double)
}
Copy the code
- After we use the correlation value, no
RawValue
Because each of uscase
All have a set of values, so you don’t need to use themRawValue
Here we useradious
,width
,height
It’s a label we picked up ourselves. We can omit it - Creates an enumeration of associated values
enum Shape { case circle(radious:Double) case rectangle(width:Double,height:Double) } var circle = Shape.circle(radious: Rectangle = Shape. Rectangle (width: 50, height: 50)Copy the code
Other uses of enumeration
Pattern matching
- use
switch
When matching enumerated values, you need to traverse all possible cases, otherwise the compiler will report an error if you don’t want to match all of themcase
, you can usedefalut
The keyword represents the default.
- Matching of associated values
enum Shape { case circle(radious:Double) case rectangle(width:Double,height:Double) } var circle = Shape.circle(radious: 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)") }Copy the code
- Matches a single association value
if case let Shape.circle(radious) = circle {
print(radious)
}
Copy the code
- different
case
The same associated value of
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}Copy the code
- Use wildcards
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
}
Copy the code
Nesting of enumerations
- Enumerations nested within enumerations
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)
}
Copy the code
Nesting in a structure
- Nested enumerations in a structure
struct Skill {
enum KeyType {
case up
case down
case left
case right
}
let key : KeyType
}
Copy the code
Enumerations contain properties and methods
- Enumerations can contain computed properties, type properties, but not storage properties
- Enumeration defines instance methods,
static
methods
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))")
}
}
Copy the code
Size of enumeration
- a
case
Size of time
Enum noMean {case a} print(MemoryLayout<noMean>. Size) print(MemoryLayout<noMean>. Stride) // The result is 0 1Copy the code
- ordinary
case
When there is no associated value, the size of the enumeration is one byte, and the maximum that a byte can represent is 255 if ourcase
Above 255, the size changes fromInt8
->Int16
If not, it will continue to double
Enum noMean {case A case B} print(MemoryLayout<noMean>. Size) print(MemoryLayout<noMean>. Stride) 1 1 // Changes the rawValue type. The print result remains unchanged. Enum noMean: String {case A case B} // The print result is 1 1Copy the code
- The size of an enumeration with associated values depends on the largest
case
Memory size, but if you look at it it should be 16, 24, 32, even numbers, but I’m adding 1 every time, so this is where we are right nowcase
It takes 1 byte. There is only onecase
By defaultsize
To zero.
enum Shape{ case circle(radious: Print (MemoryLayout<Shape>.size) print(MemoryLayout<Shape>.stride) 8 enum Shape{ case circle(radious: Double) case rectangle(width: Double, height: Print (MemoryLayout<Shape>. Size) print(MemoryLayout<Shape>. StrideCopy the code
- Print memory structure
Note that, due to byte alignment, sometimes the 1 byte of 'case' will be optimized by the compiler to be added to the previous position, and its size will not be +1Copy the code
- Let’s verify this with a little bit of code
- Modify the
circle
theradious
The type ofInt
- conclusion
- 1,
RawValue
The default size of the enumeration is 1 byte (UInt8), which means the current maximum size can be stored is 255. If this size is exceeded, the size of the current enumeration is changed fromUInt8
->UInt16
So on - 2, the enumeration size of the associated value and the maximum
case
The memory size of.
- 1,
An indirect keyword
- We want to implement a linked list through enumeration, we need to use
indirect
The keyword
- The modified version of the compiler looks like this
Indirect enum List<T> {case end case node(T, next: List<T>)} or enum List<T> {case end case node(T, next: List<T>) }Copy the code
- Enumeration is a value type, which means that its size is determined at compile time, so this process is very important for our current one
List
From a system perspective, I don’t know how much memory I’m currently allocating to this enumeration. So what? The official documentation explains it as follows
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.
- Let me print the size
- Print the memory structure of the instance object
- View the SIL file,
alloc_box
The essence of callswift_allocObjet
, soindirect
The keyword tells the compiler that my enumeration is recursive, so I’m not sure of its size, so I need to allocate a heap of memory for it.
Swift enumeration and OC mixed
Oc uses Swift enumeration
- The enumeration in OC is just an integer value, if you want to use the
Swift
Is exposed to oc and needs to be added@objc
Keyword, and the current enumeration should beInt
The type of
@objc enum Week : Int{
case MON
case TUE
}
Copy the code
- in
xxx-Swift.h
Definition in header file, import header file can be used in OC
typedef SWIFT_ENUM(NSInteger, Week, closed) {
WeekMON = 0,
WeekTUE = 1,
};
Copy the code
Swift uses OC enumeration
- Define the following three enums through OC
NS_ENUM(NSInteger, OCENUM){
Value1,
Value2
};
typedef enum{
Num1,
Num2
} OCNum;
typedef NS_ENUM(NSInteger, CEnum) {
CEnumInvalid = 0,
CEnumA = 1,
CEnumB,
CEnumC
};
Copy the code
- View the corresponding
Swift
The header file
public var OCENUM: OCENUM
public enum OCENUM : Int {
case Value1 = 0
case Value2 = 1
}
public struct OCNum : Equatable, RawRepresentable {
public init(_ rawValue: UInt32)
public init(rawValue: UInt32)
public var rawValue: UInt32
}
public enum CEnum : Int {
case invalid = 0
case A = 1
case B = 2
case C = 3
}
Copy the code