從 枚舉(enum) 到 Swift

枚舉入門

來苫幢,小明 給我說說什么是枚舉

小明: 你把手舉起來

然后呢碧信?

小明: 你看我的手 舉沒舉 ?

?

基本定義

枚舉作為 Swift 的 一等類型跛溉, 我們正好可以通過枚舉焊切, 來 一一列舉 Swift 其它 強(qiáng)有力的 類型

首先寫出枚舉的 2種表達(dá)方式

它們被放在一個(gè)大括號(hào)里,縱向排列芳室,互不干擾

enum SwiftType {
    case protocol
    case enum
    case struct
    case class
    case tuple
    case function
}

?
當(dāng)然它們也可以抱團(tuán)相擁在一起, 以 逗號(hào) 來互相敬畏

enum ProgrammingLanguage {
    case protocol, enum, struct, class, tuple, function
}

掌握以上幾種類型蛛蒙,便可呼風(fēng)喚雨

那么我就以初學(xué)者的姿態(tài)記錄一下枚舉吧

?

原始值 rawValue

Swift 的枚舉 并不會(huì)像 OC 那樣固定的賦予一個(gè)默認(rèn)的整形值,并沒有所謂的從上到下渤愁,原始值 也不是 從0到5

它們的原始值(rawValue)也可以是其它類型

enum RawValueType {
    case 整形
    case 字符
    case 字符串
    case 浮點(diǎn)型
}

但是它們必須擁有一個(gè)共同的類型原始值唯一
?

像 ProgrammingLanguage 這種沒有指明原始值類型的枚舉 沒有原始值,

它們的實(shí)例 也沒法用點(diǎn)語法 點(diǎn)出 rawValue

?

賦予原始值類型

如果想像OC 一樣 拿到原始值牵祟,我們可以指定類型

enum ProgrammingLanguage: Int {
    case Swift 
    case OC
    case Python
    case Java
}

一旦我們給定整形,也就意味著它們默認(rèn)是從0開始的

?

下一個(gè)枚舉的原始值 = 上一個(gè)枚舉的原始值 + 1

?

??只有整形是這樣 依次累加哦
?

var p = ProgrammingLanguage.OC.rawValue

print(p)
// 打印 1抖格,因?yàn)?Swift 默認(rèn)是 0

現(xiàn)在 我們做一些改動(dòng)

enum ProgrammingLanguage: Int {
    case Swift = 2
    case OC
    case Python = 6
    case Java
}

var p = ProgrammingLanguage.OC.rawValue
print(p)
// 打印 3诺苹,因?yàn)?Swift 是 2

print(p1)
// 打印 7,因?yàn)?Python 是 6

?

字符串隱式原始值

如果我們指定枚舉類型 是 String雹拄,那么其中的 case 對(duì)應(yīng)的rawValue收奔,就是它們的字符串化

enum Song: String {
    case 夏日漱石
    case 有暖氣
}

var s = Song.夏日漱石.rawValue
debugPrint(s)

// 打印 字符串 "夏日漱石"

?

rawValue 初始化

枚舉可以通過原始值 rawValue 來初始化

enum Drinking: String {
    case cola
    case sprite
    case orangeJuice
}

var dg = Drinking(rawValue: "cola")

# 注意: 這里的dg 是可選型,因?yàn)?枚舉并不知道 你傳進(jìn)去的 rawValue 是否存在

# 下面會(huì)說到滓玖,這種方式的實(shí)例化 是一個(gè)可失敗的構(gòu)造器

?

Switch 匹配枚舉值

一般來說坪哄,我們寫出枚舉 是為了區(qū)分不同的case,和 OC 一樣 Switch就成了我們 匹配枚舉值的 首選

Swift 的 枚舉情況 分為2種

// 登錄方式的枚舉
enum LoginWay {
    case Apple
    case QQ
    case Wechat
    case Weibo
}

let way = LoginWay.Apple

第一種: 窮盡所有

* 遍歷所有大括號(hào)內(nèi)的case势篡,一個(gè)不漏翩肌,不用寫defult

* 如果遺漏了,并且沒有defult 將會(huì)報(bào)錯(cuò)

switch way {
case .Apple:
    print("apple")
case .QQ:
    print("qq")
case .Wechat:
    print("wechat")
case .Weibo:
    print("weibo")
}

// 打印 "apple"

第二種: 投其所好

* 只展示部分我關(guān)心的case禁悠,其余的 用 defult 代表

* 不用展示全部

switch way {
case .QQ:
    print("qq")
case .Weibo:
    print("weibo")
default:
    print("其它")
}

// 打印 "其它"

* 關(guān)聯(lián)值

什么是關(guān)聯(lián)值 念祭?

我們來看一個(gè)栗子

// 定義一個(gè)不同交通工具 上班時(shí)間 ,我們可以自由選擇上班方式

enum OnTheWayTime {
    case bicycle(Int)     // Int    類型關(guān)聯(lián)值    的  bicycle
    case taxi(Int)        // Int    類型關(guān)聯(lián)值    的  taxi
    case bus(time: Int)   // Int    類型關(guān)聯(lián)值    的  bus
    case horse(String)    // String 類型關(guān)聯(lián)值    的  horse
}

var t = OnTheWayTime.bicycle(60)
// "實(shí)例化一個(gè)變量"碍侦,并且給成員變量 bicycle 關(guān)聯(lián) Int值 60

如果我們想要 改變 t 粱坤,也就是我們的出行方式

在t 的類型已經(jīng)確定的情況下,我們可以不用帶枚舉名稱瓷产,直接 .

t = .taxi(30)

?

我們?nèi)?Switch 遍歷 這個(gè)枚舉站玄,看一下關(guān)聯(lián)值使用方式

switch t {
case .bicycle(let bic):
    print("騎自行車上班要 \(bic) 分鐘")
case .taxi(let ti):
    print("打出租車上班要 \(ti) 分鐘")
case .bus(time: let bs):
    print("坐公交上班要 \(bs) 分鐘")
case .horse(let str):
    print("騎馬要 \(str)")
}

可以提取關(guān)聯(lián)值 用 "let / var" 修飾
通過值綁定,生成的 "局部變量"  就與 "關(guān)聯(lián)值" 相連接

?

修改t ,再去遍歷濒旦,t 是可以任意變化的

t = .horse("很久")

打又昕酢:騎馬要很久

?

optional 關(guān)聯(lián)值

optional(可選型) 是比較常用的枚舉,它的成員值 .some 也是通過關(guān)聯(lián)值的方式

var age: Int?
age = 17

switch age {
case .none:
  print("age 為 nil")
case .some(let value):
  print("age 的值是: \(value)")
}
// 打影坦馈: age 的值是 17

?

問題

關(guān)聯(lián)值 的成員 有rawValue 嗎灾常?

答案是 沒有的

因?yàn)?rawValue 是遵從了 RawRepresentable 協(xié)議,協(xié)議中通過 associatedtype來關(guān)聯(lián) rawValue, associatedtype 是用來定義 在協(xié)議中使用的 關(guān)聯(lián)類型铃拇,雖然這個(gè)關(guān)聯(lián)類型是不確定的钞瀑,但是它們是統(tǒng)一的。

有關(guān)聯(lián)值的 枚舉慷荔,它們的類型是不統(tǒng)一的雕什,所以無法使用 rawValue

?

結(jié)論

  • 我們可以把關(guān)聯(lián)值當(dāng)做一個(gè)變量,關(guān)聯(lián)之后的成員值 是可變的
  • 關(guān)聯(lián)值 和 原始值不同显晶,原始值的值 從開始 就是確定的贷岸,無法改變
    ?
  • 關(guān)聯(lián)值 無法使用 rawValue 屬性,因?yàn)樗鼈冾愋蜔o法 統(tǒng)一

?

枚舉的構(gòu)造過程

構(gòu)造過程:保證新實(shí)例在第一次使用前完成正確的初始化

除了在上述中 提到 的 rawValue 初始化,是一種隱藏了 init? 的可失敗的 構(gòu)造器之外磷雇,

我們還可以自定義 不隱藏的 init? 初始化器

enum Drinking: String {
    case cola
    case sprite
    case orangeJuice
    
    init?(str: String) {
        switch str {
        case "c":
            self = .cola
        case "s":
            self = .sprite
        case "o":
            self = .orangeJuice
        default:
        return nil
        }
    }
}

下次2種方式都可以完成初始化:

let dg = Drinking(rawValue: "cola")
// print(dg!)  cola

let gc  = Drinking(str: "s") 
// print(gc!)  sprite

?

問題

我們不是列舉了所有的情況偿警,case "c","s"唯笙,"o"螟蒸,可以不用在init后面 加 問號(hào)嗎?可以不加defult 嗎崩掘?

答案是 不可以的

雖然 我們列舉的case 是 一一俱全的七嫌,但是我們并不能保證 初始化構(gòu)造的時(shí)候 你會(huì)傳入什么東西,所以這個(gè)構(gòu)造是可能會(huì)失敗的苞慢,結(jié)果是可選的诵原,所以就得加 ? 挽放,就需要defult來 處理不存在的 case

?

枚舉的屬性

計(jì)算屬性

來绍赛,看栗子

吃開封菜的時(shí)候到了

通過對(duì) kfc 的點(diǎn)單方式 單點(diǎn)/套餐 我們寫了一個(gè)枚舉,外界通過調(diào)用實(shí)例的 description 來獲得 描述

enum KFCFood {
    case familyFood(Int)
    case Other(String, String, String)
    
    var description: String {
        switch self {
        case .familyFood(let num):
            return "今天我一個(gè)人吃了 \(num) 個(gè)全家桶"
        case let .Other(s1, s2, s3):
            return "今天晚餐吃了\(s1)  \(s2) 還有 \(s3)"
        }
    }
}

var k = KFCFood.familyFood(2)
print(k.description) // 今天我一個(gè)人吃了 2 個(gè)全家桶


k = .Other("漢堡", "可樂", "薯?xiàng)l")
print(k.description) // 今天晚餐吃了漢堡  可樂 還有 薯?xiàng)l
ps: 可樂 漢堡 和薯?xiàng)l 不也是套餐嗎 你個(gè)low 狗

我們定義了一個(gè) KFC 的枚舉

通過 關(guān)聯(lián)值 + 計(jì)算屬性 來 存儲(chǔ) 以及 獲得 description

?

小結(jié)

  • 因?yàn)檫@里有關(guān)聯(lián)值辑畦,所以沒法通過 rawValue的方式 初始化惹资,也就是說如果通過關(guān)聯(lián)值初始化,就意味著 得到的實(shí)例 都是存在的航闺,switch 里 不需要 defult

case let .Other(s1, s2, s3):

  • 如果說關(guān)聯(lián)值得個(gè)數(shù) 不止一個(gè)褪测,那么我們使用的時(shí)候,可以把修飾 局部變量的let/var 提到 最前面

?

擴(kuò)展 和協(xié)議 的第二種寫法

我們也可以 使用協(xié)議(Protocols)和協(xié)議擴(kuò)展(Protocol Extension)

高大上 有沒有

通過協(xié)議 以及 協(xié)議擴(kuò)展可以更好的 將 成員值 與 屬性/方法 實(shí)現(xiàn)分離開潦刃,
代碼也就自然而然的 通俗易懂了

enum KFCFood {
    case familyFood(Int)
    case Other(String, String, String)
}

protocol EatFood {
    var description: String { get }
}

extension KFCFood: EatFood {
    var description: String {
         switch self {
         case .familyFood(let num):
             return "今天我一個(gè)人吃了 \(num) 個(gè)全家桶"
         case let .Other(s1, s2, s3):
             return "今天晚餐吃了\(s1)  \(s2) 還有 \(s3)"
         }
     }
}

?

枚舉的方法

我們可以像在類中定義方法一樣侮措,在枚舉中我們也可以定義方法

enum Song: String {
    case chinese
    case english
    func getName() -> String {
        switch self {
        case .chinese:
            return "chinese"
        case.english:
            return "english"
        }
    }
}

let s  = Song.chinese
print(s.getName())
// 打印 chinese

那么如果我們想在方法內(nèi)改變 自身的值呢?

比如 我們想中文歌 和 英文歌 來回切換

類似這樣

enum Song: String {
    case chinese
    case english
     func getChange() {
        switch self {
        case .chinese:
            self = .english
            // 切換英文歌
        case.english:
            self = .chinese
            // 切換中文歌
        }
    }
}

當(dāng)我們編譯的時(shí)候 就會(huì)發(fā)現(xiàn) 報(bào)錯(cuò)了

# Cannot assign to value: 'self' is immutable

這個(gè)時(shí)候我們就用到 mutating了

mutating

func 前面加上 mutating ,我們就可以在值類型中 改變自身的值了

總結(jié)

參考鏈接

SwiftGG

如果有新的知識(shí) 我還會(huì)補(bǔ)充進(jìn)來

以上都是我個(gè)人的一些看法乖杠,可能有不對(duì)的地方

都是第一次學(xué)Swift 分扎,還請(qǐng)多多指教!胧洒!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畏吓,一起剝皮案震驚了整個(gè)濱河市墨状,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菲饼,老刑警劉巖肾砂,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宏悦,居然都是意外死亡镐确,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門饼煞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來源葫,“玉大人,你說我怎么就攤上這事砖瞧∠⑻茫” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵块促,是天一觀的道長(zhǎng)储矩。 經(jīng)常有香客問我,道長(zhǎng)褂乍,這世上最難降的妖魔是什么持隧? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮逃片,結(jié)果婚禮上屡拨,老公的妹妹穿的比我還像新娘。我一直安慰自己褥实,他們只是感情好呀狼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布萨蚕。 她就那樣靜靜地躺著粹胯,像睡著了一般缅糟。 火紅的嫁衣襯著肌膚如雪囤热。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天废累,我揣著相機(jī)與錄音十气,去河邊找鬼丧蘸。 笑死窟勃,一個(gè)胖子當(dāng)著我的面吹牛祖乳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秉氧,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼眷昆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起亚斋,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤作媚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后帅刊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纸泡,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年厚掷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弟灼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片级解。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冒黑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勤哗,到底是詐尸還是另有隱情抡爹,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布芒划,位于F島的核電站冬竟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏民逼。R本人自食惡果不足惜泵殴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拼苍。 院中可真熱鬧笑诅,春花似錦、人聲如沸疮鲫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俊犯。三九已至妇多,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燕侠,已是汗流浹背者祖。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绢彤,地道東北人咸包。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像杖虾,于是被迫代替她去往敵國(guó)和親烂瘫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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