Swift底層原理探索2----枚舉

枚舉的基本你用法

enum Direction_1 {
    case north, south, east, west
}

enum Direction {
    case north
    case south
    case east
    case west
}
var dir = Direction.west
dir = Direction.east
dir = .north
print(dir)

switch dir {
case .north:
    print("north")
case .south:
    print("south")
case .east:
    print("east")
case .west:
    print("west")
}


關(guān)聯(lián)值(Associated Values)

關(guān)聯(lián)值是直接存在枚舉變量的內(nèi)存里面的疮绷,這點(diǎn)要牢記,對(duì)于一個(gè)有固定取值范圍的變量棒动,設(shè)計(jì)成枚舉比較合適

enum Score {
    case points(Int)
    case grade(Character)
}
var score = Score.points(96)
score = .grade("A")

switch score {
case let .points(i):
    print(i, "points")
case let .grade(i):
    print("grade", i)
} // grade A

enum Date {
    case digit(year: Int, month: Int, day: Int)
    case string(String)
}
var date = Date.digit(year: 2020, month: 02, day: 29)
date = .string("2020-02-29")
switch date {
case let .digit(year, month, day):  
    print(year, month, day)
case let .string(dateStr):
    print(dateStr)
    
} // "2020-02-29"

注意上看switch內(nèi)部對(duì)let/var關(guān)鍵字的使用贿条,如果下載枚舉值左邊今魔,那么關(guān)聯(lián)值只能統(tǒng)一綁定給let常量或者var變量

case let .digit(year, month, day): //year、month顷级、day都是let常量
case var .digit(year, month, day): //year凫乖、month、day都是var變量

如果let/var關(guān)鍵字寫在關(guān)聯(lián)值括號(hào)內(nèi)弓颈,就比較靈活

case .digit(let year, var month, let day)

另外一些枚舉舉例

enum Password {
    case number(Int, Int, Int, Int)
    case gesture(String)
}
var pwd = Password.number(3, 5, 7, 9)
pwd = .gesture("3259")
switch pwd {
case let .number(n1 , n2 , n3 , n4 ): //數(shù)字密碼
    print("number is", n1, n2, n3, n4)
case let .gesture(pwdStr):// 字符串密碼
    print("gestrue is", pwdStr)
}


原始值(Raw Values)

枚舉成員可以只用相同類型的默認(rèn)值預(yù)先關(guān)聯(lián)帽芽,這個(gè)默認(rèn)值叫做 原始值

enum PokerSuit: Character { //這里的Character表示的是枚舉值所關(guān)聯(lián)的原始值
    case spade = "?"
    case heart = "?"
    case diamond = "?"
    case club = "?"
}
var suit = PokerSuit.spade
print(suit)
print(suit.rawValue)
print(PokerSuit.club.rawValue)

enum Grade: String {
    case perfect = "A"
    case great = "B"
    case good = "C"
    case bad = "D"
}
print(Grade.perfect.rawValue) // A
print(Grade.great.rawValue) // B
print(Grade.good.rawValue) // C
print(Grade.bad.rawValue) // D


隱式原始值(Implicitly Assigned Raw Values)

enum Direction1: String {
    case north, south, east, west
}
print(Direction1.north.rawValue)

enum Direction2: String {
    case north = "nor", south, east, west
}
print(Direction2.north.rawValue)//有賦值,就用賦值的字符串
print(Direction2.south.rawValue)//沒賦值翔冀, 就用case名字符串

enum Season: Int {
    case spring, summer, autumn, winter
}
print(Season.spring.rawValue)//0
print(Season.summer.rawValue)//1
print(Season.autumn.rawValue)//2
print(Season.winter.rawValue)//3

enum Season2: Int {
    case spring = 2, summer, autumn = 6, winter
}
print(Season2.spring.rawValue) //2
print(Season2.summer.rawValue) //3
print(Season2.autumn.rawValue) //6
print(Season2.winter.rawValue) //7


遞歸枚舉(Recursive Enumeration)

//書寫方法一
indirect enum ArithExpr_1 {
    case number(Int)
    case sum(ArithExpr, ArithExpr)
    case difference(ArithExpr, ArithExpr)
}

//書寫方法二
enum ArithExpr {
    case number(Int)
    indirect case sum(ArithExpr, ArithExpr)
    indirect case difference(ArithExpr, ArithExpr)
}

let five = ArithExpr.number(5)
let four = ArithExpr.number(4)
let two = ArithExpr.number(2)
let sum = ArithExpr.sum(five, four)
let difference = ArithExpr.difference(sum, two)


func calculate(_ expr: ArithExpr) -> Int{
    switch expr {
    case let .number(value):
        return value
    case let .sum(left, right):
        return calculate(left) + calculate(right)
    case let .difference(left, right):
        return calculate(left) - calculate(right)
    }
}


MemoryLayout

我們可以使用 MemoryLayout 來獲取數(shù)據(jù)類型占用的內(nèi)存大小导街,相當(dāng)于C里面使用的sizeof

enum Password2 {
    case number(Int, Int, Int, Int)
    case other
}
MemoryLayout<Password2>.stride //系統(tǒng)分配給變量的內(nèi)存大小--40
MemoryLayout<Password2>.size //實(shí)際被使用的內(nèi)存大小--33
MemoryLayout<Password2>.alignment //對(duì)其參數(shù)--8

var pd = Password2.number(9, 8, 7, 6)
pd = .other
print(pd) //"other/n"
MemoryLayout.stride(ofValue: pd)  //40
MemoryLayout.size(ofValue: pd)  //33
MemoryLayout.alignment(ofValue: pd)  //8


枚舉在內(nèi)存中是如何存儲(chǔ)的?

通過MemoryLayout纤子,我們只能簡(jiǎn)單查看一些內(nèi)存相關(guān)的信息搬瑰,但還不足以看清枚舉在內(nèi)存中的具體細(xì)節(jié),由于Xcode調(diào)試工具無法為我們提供枚舉變量的內(nèi)存地址控硼,因此需要借助一些額外的工具泽论,這里推介一下大牛李明杰的一個(gè)工具

(1)首先來看下一種簡(jiǎn)單的情況~~~~~~~

enum TestEnum {
    case test1, test2, test3
}
print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.test1
print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t)) //這里可以輸出變量t的內(nèi)存地址
t = .test2
t = .test3
print("Stop for debug")

Mems.ptr(ofVal: &t)可以幫我們獲得變量t的內(nèi)存地址卡乾,準(zhǔn)備好3個(gè)斷點(diǎn)

image

然后將程序運(yùn)行值斷點(diǎn)1處翼悴,此時(shí)我們已經(jīng)獲得t的內(nèi)存地址,根據(jù)該地址幔妨,調(diào)出內(nèi)存界面鹦赎,我們來觀察一下此時(shí)的內(nèi)存細(xì)節(jié)
image

在繼續(xù)走到斷點(diǎn)2、斷點(diǎn)3處陶冷,對(duì)比一下各自的內(nèi)存情況如下
image

在這里插入圖片描述

小結(jié):enum TestEnum { case test1, test2, test3 }

  • 系統(tǒng)為TestEnum類型的變量分配1個(gè)字節(jié)的內(nèi)存空間
  • test1 钙姊、 test2、 test3 三個(gè)case對(duì)應(yīng)在內(nèi)存中用整數(shù)0埂伦、1煞额、2來表示

(2)把場(chǎng)景調(diào)整為有Int型原始值的情形如下~~~~~~~

enum TestEnum: Int {
    case test1
    case test2 = 3
    case test3
    case test4 = 10
    case test5
}
print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.test1
print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t)) //這里可以輸出變量t的內(nèi)存地址
t = .test2
t = .test3
t = .test4
t = .test5
print("Stop for debug")

按照上面同樣的方法,對(duì)比各自case的內(nèi)存情況如下

image

image

image

image

image

我們?cè)诓榭匆幌赂髯?code>case的rawValue

print("test1的rawValue:", TestEnum.test1.rawValue)
print("test2的rawValue:", TestEnum.test2.rawValue)
print("test2的rawValue:", TestEnum.test3.rawValue)
print("test2的rawValue:", TestEnum.test4.rawValue)
print("test2的rawValue:", TestEnum.test5.rawValue)

***********運(yùn)行結(jié)果
test1的rawValue: 0
test2的rawValue: 3
test2的rawValue: 4
test2的rawValue: 10
test2的rawValue: 11

看得出沾谜,如果原始值類型為Int

  • 那么在不手動(dòng)設(shè)定的情況下膊毁,首個(gè)case的原始值默為整數(shù)0,非首個(gè)case的默認(rèn)值為上一個(gè)case的默認(rèn)值+1
  • 如果手動(dòng)設(shè)定了基跑,那么原始值即為設(shè)定值婚温。

(3)看過了帶Int型原始值的情況之后,在看一下帶String型原始值的情況媳否,改造如下~~~~~~~

enum TestEnum: String {
    case test1
    case test2 = "AA"
    case test3 = "漢字"
    case test4 = "??"
    case test5
}
print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.test1
print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t)) //這里可以輸出變量t的內(nèi)存地址
t = .test2
t = .test3
t = .test4
t = .test5
print("Stop for debug")


print("test1的rawValue:", TestEnum.test1.rawValue)
print("test2的rawValue:", TestEnum.test2.rawValue)
print("test2的rawValue:", TestEnum.test3.rawValue)
print("test2的rawValue:", TestEnum.test4.rawValue)
print("test2的rawValue:", TestEnum.test5.rawValue)

****************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 1
實(shí)際使用的內(nèi)存 1
內(nèi)存對(duì)齊參數(shù) 1
枚舉變量t的內(nèi)存地址: 0x0000000100008218
Stop for debug
test1的rawValue: test1
test2的rawValue: AA
test2的rawValue: 漢字
test2的rawValue: ??
test2的rawValue: test5
Program ended with exit code: 0

內(nèi)存的情況這里省略栅螟,和上面Int型的時(shí)候是一樣的荆秦,根據(jù)調(diào)試輸出的情況,我們可以看出

  • 如果不設(shè)置原始值力图,那么case的原始值為該case名稱的字符串
  • 如果設(shè)置了原始值步绸,那嗎case的原始值即為設(shè)定值

總結(jié) 帶原始值的枚舉

  • 枚舉變量本身的就占一個(gè)字節(jié)
  • 枚舉變量所對(duì)應(yīng)的內(nèi)存里所存放的具體值:對(duì)應(yīng)第一個(gè)case為0,并且往后逐個(gè)+1

(4)帶關(guān)聯(lián)值的場(chǎng)景~~~~~~~

enum TestEnum {
    case test1(a: Int, b: Int, c: Int)
    case test2(d: Int, e: Int)
    case test3(f: Int)
    case test4(g: Bool)
    case test5
}
print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.test1(a: 1, b: 2, c: 3)
//這里可以輸出變量t的內(nèi)存地址
print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t))
t = .test2(d: 4, e: 5)
t = .test3(f: 6)
t = .test4(g: true)
t = .test5
print("Stop for debug")

*****************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 32
實(shí)際使用的內(nèi)存 25
內(nèi)存對(duì)齊參數(shù) 8
枚舉變量t的內(nèi)存地址: 0x0000000100008208

接下來照例在過一遍內(nèi)存吃媒,下面直接貼上內(nèi)存查看的結(jié)果

  • t = test1(a: 1, b: 2, c: 3)
01 00 00 00 00 00 00 00  --> 對(duì)應(yīng)a
02 00 00 00 00 00 00 00  --> 對(duì)應(yīng)b
03 00 00 00 00 00 00 00  --> 對(duì)應(yīng)c
00 00 00 00 00 00 00 00  --> 對(duì)應(yīng)case test1
  • t = test2(d: 4, e: 5)
04 00 00 00 00 00 00 00  --> 對(duì)應(yīng)d
05 00 00 00 00 00 00 00  --> 對(duì)應(yīng)e
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
01 00 00 00 00 00 00 00  --> 對(duì)應(yīng)case test2
  • t = test3(f: 6)
06 00 00 00 00 00 00 00  --> 對(duì)應(yīng)f
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
02 00 00 00 00 00 00 00  --> 對(duì)應(yīng)case test3
  • t = test4(g: true)
01 00 00 00 00 00 00 00  --> 對(duì)應(yīng)g
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
03 00 00 00 00 00 00 00  --> 對(duì)應(yīng)case test4
  • t = test5
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
00 00 00 00 00 00 00 00  --> 此時(shí)沒用到
04 00 00 00 00 00 00 00  --> 對(duì)應(yīng)case test5

總結(jié) 帶關(guān)聯(lián)值的枚舉

  • 枚舉變量的成員case的值只用了其內(nèi)存空間的1字節(jié)來存放
  • 枚舉的case關(guān)聯(lián)值也存放在枚舉變量的內(nèi)存中
  • 系統(tǒng)為枚舉的case關(guān)聯(lián)值所分配的內(nèi)存空間瓤介,必須保證可以放下所需內(nèi)存最大的那個(gè)關(guān)聯(lián)值
  • 枚舉變量的內(nèi)存空間里,先存放存放的是case關(guān)聯(lián)值赘那,成員case的值被放在最后
  • 枚舉變量的內(nèi)存總空間按內(nèi)存對(duì)齊參數(shù)進(jìn)行補(bǔ)齊(計(jì)算機(jī)常識(shí))

(5)一些極端場(chǎng)景~~~~~~~

enum TestEnum {
    case test
}

print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)
var t = TestEnum.test
print(print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t)))

****************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 1
實(shí)際使用的內(nèi)存 0
內(nèi)存對(duì)齊參數(shù) 1
枚舉變量t的內(nèi)存地址: 0x0000000000000001
Program ended with exit code: 0

可以看到刑桑,系統(tǒng)確實(shí)是分配了1個(gè)字節(jié)給枚舉,但是實(shí)際上用到了0個(gè)募舟,因?yàn)橐环N情況不需要做任何區(qū)分祠斧,所以也就不需要存儲(chǔ),當(dāng)然貌似沒人會(huì)這么用拱礁,所以系統(tǒng)針對(duì)這種情況下的處理梁肿,就不難理解了。在看看帶關(guān)聯(lián)值的情況:

enum TestEnum {
    case test(Int)
}

print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)
var t = TestEnum.test(10)
print("枚舉變量t的內(nèi)存地址:",Mems.ptr(ofVal: &t))
print("Stop for debug")

***************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 8
實(shí)際使用的內(nèi)存 8
內(nèi)存對(duì)齊參數(shù) 8
枚舉變量t的內(nèi)存地址: 0x0000000100007200
Stop for debug
Program ended with exit code: 0

***************匯編結(jié)果
0A 00 00 00 00 00 00 00 

可以看到系統(tǒng)直接分配了8個(gè)字節(jié)來存儲(chǔ)枚舉里面的Int型關(guān)聯(lián)值觅彰,沒有分配空間來存儲(chǔ)成員case的值吩蔑,原因和上面很想,因?yàn)楝F(xiàn)在就是一種case填抬,沒有必要再存儲(chǔ)成員變量的值烛芬,只需要關(guān)心case關(guān)聯(lián)值就好。那如果有一個(gè)以上的case飒责,是不是就會(huì)給成員case分配空間了赘娄?咱們?cè)囋嚳矗缦?/p>

enum TestEnum {
    case other
    case test(Int)
}

print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.other
//Mem.memStr是大神李明杰提供的工具宏蛉,文中有鏈接遣臼,可以幫我直接獲取變量的內(nèi)存里面的值
print("枚舉變量t = other 時(shí)的內(nèi)存情況:  ",Mems.memStr(ofVal: &t)) 
t = TestEnum.test(10)
print("枚舉變量t = test(10)時(shí)的內(nèi)存地址:",Mems.memStr(ofVal: &t))
print("Stop for debug")

***************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 16
實(shí)際使用的內(nèi)存 9
內(nèi)存對(duì)齊參數(shù) 8
枚舉變量t = other 時(shí)的內(nèi)存情況:   0x0000000000000000 0x0000000000000001
枚舉變量t = test(10)時(shí)的內(nèi)存地址: 0x000000000000000a 0x0000000000000000

可以看出,只要case大于1個(gè)拾并,除了Int型關(guān)聯(lián)值需要占用8個(gè)字節(jié)外揍堰,枚舉變量還使用了1個(gè)字節(jié)來存儲(chǔ)成員case的值,根據(jù)內(nèi)存對(duì)齊參數(shù)8嗅义,系統(tǒng)給枚舉變量分配了16字節(jié)空間屏歹。上面的結(jié)果中,最后一個(gè)字節(jié)是用來存放成員case的值也就是case other 對(duì)應(yīng)了01之碗, case test 對(duì)應(yīng)了00蝙眶,但是感覺順序不太對(duì),明明是other在前褪那,test在后的幽纷,帶著這個(gè)疑問式塌,我們把用例改造如下

enum TestEnum {
    case aaa
    case test(Int)
    case ccc
    case test3(Int, Int)
    case test2(Int,Int, Int)
    case other
}
print("系統(tǒng)實(shí)際分配內(nèi)存",MemoryLayout<TestEnum>.stride)
print("實(shí)際使用的內(nèi)存",MemoryLayout<TestEnum>.size)
print("內(nèi)存對(duì)齊參數(shù)",MemoryLayout<TestEnum>.alignment)

var t = TestEnum.aaa
print("t = .aaa的內(nèi)存情況:              ",Mems.memStr(ofVal: &t))
t = TestEnum.test(10)
print("t = .test(10)的內(nèi)存情況:         ",Mems.memStr(ofVal: &t))
t = TestEnum.ccc
print("t = .ccc的內(nèi)存情況:              ",Mems.memStr(ofVal: &t))
t = TestEnum.test3(16, 32)
print("t = .test3(16, 32)的內(nèi)存情況:    ",Mems.memStr(ofVal: &t))
t = TestEnum.test2(20, 20, 20)
print("t = .test2(20, 20, 20)的內(nèi)存情況:",Mems.memStr(ofVal: &t))
t = TestEnum.other
print("t = .other的內(nèi)存情況:            ",Mems.memStr(ofVal: &t))
print("Stop for debug")



*************************************運(yùn)行結(jié)果
系統(tǒng)實(shí)際分配內(nèi)存 32
實(shí)際使用的內(nèi)存 25
內(nèi)存對(duì)齊參數(shù) 8
t = .aaa的內(nèi)存情況:               0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000003
t = .test(10)的內(nèi)存情況:          0x000000000000000a 0x0000000000000000 0x0000000000000000 0x0000000000000000
t = .ccc的內(nèi)存情況:               0x0000000000000001 0x0000000000000000 0x0000000000000000 0x0000000000000003
t = .test3(16, 32)的內(nèi)存情況:     0x0000000000000010 0x0000000000000020 0x0000000000000000 0x0000000000000001
t = .test2(20, 20, 20)的內(nèi)存情況: 0x0000000000000014 0x0000000000000014 0x0000000000000014 0x0000000000000002
t = .other的內(nèi)存情況:             0x0000000000000002 0x0000000000000000 0x0000000000000000 0x0000000000000003
Stop for debug
Program ended with exit code: 0

從上面的調(diào)試,又挖掘了一點(diǎn)小細(xì)節(jié):


image
  • 對(duì)于有關(guān)聯(lián)值的成員case友浸,它的case值會(huì)根據(jù)定義的順序珊搀,默認(rèn)從0開始+1累加,
  • 其余所有不帶關(guān)聯(lián)值的成員case尾菇,它們的case值相同,而且都等于最后一個(gè)可關(guān)聯(lián)成員case 的值+1


關(guān)聯(lián)值 VS 原始值rawValue

以上我們看清楚了簡(jiǎn)單枚舉囚枪、關(guān)聯(lián)值枚舉派诬、原始值枚舉在內(nèi)存中分別是如何存儲(chǔ)的,可以看出链沼,枚舉的關(guān)聯(lián)值和原始值又以下區(qū)別:

  • 內(nèi)存角度:關(guān)聯(lián)值是直接存儲(chǔ)在枚舉變量?jī)?nèi)存里面的默赂,而原始值則不是,因?yàn)樵贾凳峭ㄟ^xx.rawValue訪問的括勺,因此它的值完全不需要存儲(chǔ)缆八,可以在枚舉定義完之后通過方法提供給外部。
  • 使用角度:原始值必須在枚舉定義的時(shí)候確定原始值類型疾捍,才能被使用 enum Direction : String/Int/... {...}奈辰。關(guān)聯(lián)值則必須在枚舉定義的時(shí)候,確定好case所對(duì)應(yīng)的關(guān)聯(lián)值類型
  • 賦值:關(guān)聯(lián)值只能在枚舉case被賦值給變量的時(shí)候進(jìn)行賦值乱豆,因?yàn)橥粋€(gè)case每次被賦值給變量奖恰,都需要設(shè)定一個(gè)關(guān)聯(lián)值,因此也可以說關(guān)聯(lián)值是可以改變的宛裕,如下
enum Score {
    case points(Int)
    case grade(Character)
}
var score = Score.points(96)
score = .grade("A")
score = .grade("B") -->相同的case瑟啃,不同的關(guān)聯(lián)值

而原始值,只能在枚舉定義的時(shí)候進(jìn)行賦值揩尸,不賦值則系統(tǒng)會(huì)給定相應(yīng)的默認(rèn)值蛹屿,也就是只有一次機(jī)會(huì)可以賦值,定義完枚舉之后岩榆,就沒有辦法可以更改原始值了错负,示例如下

enum Grade: String {
    case perfect = "A"
    case great
    case good = "C"
    case bad = "D"
}
print(Grade.perfect.rawValue) --> A
print(Grade.great.rawValue) --> 定義時(shí)無賦值,系統(tǒng)默認(rèn)為case的名稱 great
print(Grade.good.rawValue) --> C
print(Grade.bad.rawValue) -> D


switch的實(shí)現(xiàn)原理(待續(xù)...)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勇边,一起剝皮案震驚了整個(gè)濱河市湿颅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粥诫,老刑警劉巖油航,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異怀浆,居然都是意外死亡谊囚,警方通過查閱死者的電腦和手機(jī)怕享,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镰踏,“玉大人函筋,你說我怎么就攤上這事〉煳保” “怎么了跌帐?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)绊率。 經(jīng)常有香客問我谨敛,道長(zhǎng),這世上最難降的妖魔是什么滤否? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任脸狸,我火速辦了婚禮,結(jié)果婚禮上藐俺,老公的妹妹穿的比我還像新娘炊甲。我一直安慰自己,他們只是感情好欲芹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布卿啡。 她就那樣靜靜地躺著,像睡著了一般菱父。 火紅的嫁衣襯著肌膚如雪牵囤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天滞伟,我揣著相機(jī)與錄音讯沈,去河邊找鬼红省。 笑死穿香,一個(gè)胖子當(dāng)著我的面吹牛袜蚕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亩钟,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼乓梨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了清酥?” 一聲冷哼從身側(cè)響起扶镀,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焰轻,沒想到半個(gè)月后臭觉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年蝠筑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狞膘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡什乙,死狀恐怖挽封,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情臣镣,我是刑警寧澤辅愿,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站忆某,受9級(jí)特大地震影響点待,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褒繁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馍忽。 院中可真熱鬧棒坏,春花似錦、人聲如沸遭笋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓦呼。三九已至喂窟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間央串,已是汗流浹背磨澡。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留质和,地道東北人稳摄。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饲宿,于是被迫代替她去往敵國(guó)和親厦酬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容