C語言枚舉
enum 枚舉名 {
枚舉值1,
枚舉值2,
……};
一周七天可以寫成
enum week
{
MON, TUE, WED, THU, FRI, SAT, SUN
};
第?個(gè)枚舉成員的默認(rèn)值為整型的 0,后?的枚舉值依次類推憋活,如果我們想更改,只需要這樣操作
enum week
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
那如何定義?個(gè)枚舉變量
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
}
上述代碼也可以直接?個(gè) case ,然后?逗號隔開
enum week{
case MONDAY, TUEDAY, WEDDAY, THUDAY, FRIDAY, SATDAY, SUNDAY
}
枚舉值默認(rèn)是整形,也以表達(dá)為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)
,,如果我們不想寫后?的字符串糠惫,這個(gè)時(shí)候我們就 可以使? 隱? 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
當(dāng)改成String型之后拉盾,打印的值就變成了當(dāng)前枚舉值了。
通過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調(diào)用了get方法仍侥,7%將%5也就是枚舉值MON傳參進(jìn)去
// week.rawValue.getter
sil hidden @main.week.rawValue.getter : Swift.String : $@convention(method) (week) -> @owned String {
// %0 // users: %2, %1
bb0(%0 : $week):
//聲明一個(gè)變量self要出,等于參數(shù)week
debug_value %0 : $week, let, name "self", argno 1 // id: %1
//匹配枚舉值,跳轉(zhuǎn)到對應(yīng)的分支
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
//創(chuàng)建String农渊,跳轉(zhuǎn)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
患蹂,但是一個(gè)是枚舉類型,一個(gè)是字符串類型
枚舉的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
//構(gòu)建元組砸紊,存放字符串?dāng)?shù)組和指針地址
%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
//通過方法來進(jìn)行匹配
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
//不成功繼續(xù)匹配
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)
}
只要實(shí)現(xiàn)了CaseIterable
協(xié)議就可以醉顽。
關(guān)聯(lián)值
如果我們想?枚舉表達(dá)更復(fù)雜的信息沼溜,?不僅僅是?個(gè) RawValue
這么簡單,這個(gè)時(shí)候我們就可以使? Associated Value
,當(dāng)聲明了關(guān)聯(lián)值后游添,就無法使用init
和RawValue
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)
}
//也可以單獨(dú)取出來用
if case let Shape.circle(radious) = circle{
print(radious)
}
當(dāng)我們只關(guān)注不同枚舉值的相同關(guān)聯(lián)值
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")
}
注意系草,前后變量要一一對應(yīng)。不關(guān)注的也以用_
來省略
枚舉的嵌套
枚舉中含有枚舉
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)
結(jié)構(gòu)體中包含枚舉
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
中能包含計(jì)算屬性唆涝,類型屬性悄但。不能包含存儲屬性
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)!
}
}
}
枚舉的大小
枚舉的大小取決于枚舉值,默認(rèn)是UInt8大小石抡,也就是一字節(jié)檐嚣,超過UInt8容量就會升級為UInt16,也就是二字節(jié)啰扛,以此類推嚎京。
存在關(guān)聯(lián)值,取決最大case的大小
enum Shape{
case circle(radious: Double)
case rectangle(width: Int)
}
print(MemoryLayout<Shape>.stride)
print(MemoryLayout<Shape>.size)
·····
16
9
Double占8字節(jié)隐解,加上case的1字節(jié)鞍帝,就是9字節(jié),根據(jù)字節(jié)對齊煞茫,所以步長是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字節(jié)
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
通過打印地址摄凡,發(fā)現(xiàn)把聲明了indirect
關(guān)鍵字的值放在了堆空間上。
查看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.
在堆上分配一個(gè)引用計(jì)數(shù)的@box蚓曼,其大小足以容納類型T的值亲澡,以及retain計(jì)數(shù)和運(yùn)行時(shí)所需的任何其他元數(shù)據(jù)。該指令的結(jié)果是引用計(jì)數(shù)的@box引用纫版,該引用擁有該框床绪。project_box指令用于檢索框內(nèi)值的地址。
OC-Swift混編
我們在Swift的枚舉前加上@objc
就可以了
@objc enum WEEK: Int {
case MON, TUE
}
編譯一下其弊,我們就可以在.h文件中查看
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
來聲明,就會編譯成結(jié)構(gòu)體
**********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
}