從 枚舉(enum) 到 Swift ,初學者就剛恰好

枚舉入門git

來,小明 給我說說什麼是枚舉

小明: 你把手舉起來

而後呢?

小明: 你看個人手 舉沒舉 ?
複製代碼

 

基本定義

枚舉做爲 Swift 的 一等類型, 咱們正好能夠經過枚舉, 來 一一列舉 Swift 其它 強有力的 類型swift

首先寫出枚舉的 2種表達方式bash

它們被放在一個大括號裏,縱向排列,互不干擾app

enum SwiftType {
    case protocol
    case enum
    case struct
    case class
    case tuple
    case function
}
複製代碼

  固然它們也能夠抱團相擁在一塊兒, 以 逗號 來互相敬畏工具

enum ProgrammingLanguage {
    case protocol, enum, struct, class, tuple, function
}
複製代碼

掌握以上幾種類型,即可呼風喚雨ui

那麼我就以初學者的姿態記錄一下枚舉吧spa

 

原始值 rawValue

Swift 的枚舉 並不會像 OC 那樣固定的賦予一個默認的整形值,並無所謂的從上到下,原始值 也不是 從0到5debug

它們的原始值(rawValue)也能夠是其它類型code

enum RawValueType {
    case 整形
    case 字符
    case 字符串
    case 浮點型
}
複製代碼

可是它們必須擁有一個共同的類型原始值惟一  ip

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

它們的實例 也無法用點語法 點出 rawValue

 

賦予原始值類型

若是想像OC 同樣 拿到原始值,咱們能夠指定類型

enum ProgrammingLanguage: Int {
    case Swift 
    case OC
    case Python
    case Java
}
複製代碼

一旦咱們給定整形,也就意味着它們默認是從0開始的

 

下一個枚舉的原始值 = 上一個枚舉的原始值 + 1

 

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

var p = ProgrammingLanguage.OC.rawValue

print(p)
// 打印 1,由於 Swift 默認是 0
複製代碼

如今 咱們作一些改動

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

var p = ProgrammingLanguage.OC.rawValue
print(p)
// 打印 3,由於 Swift 是 2

print(p1)
// 打印 7,由於 Python 是 6
複製代碼

 

字符串隱式原始值

若是咱們指定枚舉類型 是 String,那麼其中的 case 對應的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 是可選型,由於 枚舉並不知道 你傳進去的 rawValue 是否存在

# 下面會說到,這種方式的實例化 是一個可失敗的構造器
複製代碼

 

Switch 匹配枚舉值

通常來講,咱們寫出枚舉 是爲了區分不一樣的case,和 OC 同樣 Switch就成了咱們 匹配枚舉值的 首選

Swift 的 枚舉狀況 分爲2種

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

let way = LoginWay.Apple
複製代碼

第一種: 窮盡全部

* 遍歷全部大括號內的case,一個不漏,不用寫defult

* 若是遺漏了,而且沒有defult 將會報錯

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

// 打印 "apple"
複製代碼

第二種: 投其所好

* 只展現部分我關心的case,其他的 用 defult 表明

* 不用展現所有

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

// 打印 "其它"
複製代碼

* 關聯值

什麼是關聯值 ?

咱們來看一個栗子

// 定義一個不一樣交通工具 上班時間 ,咱們能夠自由選擇上班方式

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

var t = OnTheWayTime.bicycle(60)
// "實例化一個變量",而且給成員變量 bicycle 關聯 Int值 60
複製代碼

若是咱們想要 改變 t ,也就是咱們的出行方式

在t 的類型已經肯定的狀況下,咱們能夠不用帶枚舉名稱,直接 .

t = .taxi(30)

 

咱們去 Switch 遍歷 這個枚舉,看一下關聯值使用方式

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)")
}

能夠提取關聯值 用 "let / var" 修飾
經過值綁定,生成的 "局部變量"  就與 "關聯值" 相鏈接
複製代碼

 

修改t ,再去遍歷,t 是能夠任意變化的

t = .horse("好久")

打印:騎馬要好久

 

optional 關聯值

optional(可選型) 是比較經常使用的枚舉,它的成員值 .some 也是經過關聯值的方式

var age: Int?
age = 17

switch age {
case .none:
  print("age 爲 nil")
case .some(let value):
  print("age 的值是: \(value)")
}
// 打印: age 的值是 17
複製代碼

 

問題

關聯值 的成員 有rawValue 嗎?

答案是 沒有的

由於 rawValue 是聽從了 RawRepresentable 協議,協議中經過 associatedtype來關聯 rawValue, associatedtype 是用來定義 在協議中使用的 關聯類型,雖然這個關聯類型是不肯定的,可是它們是統一的。

有關聯值的 枚舉,它們的類型是不統一的,因此沒法使用 rawValue

 

結論

  • 咱們能夠把關聯值當作一個變量,關聯以後的成員值 是可變的
  • 關聯值 和 原始值不一樣,原始值的值 從開始 就是肯定的,沒法改變  
  • 關聯值 沒法使用 rawValue 屬性,由於它們類型沒法 統一

 

枚舉的構造過程

構造過程:保證新實例在第一次使用前完成正確的初始化

除了在上述中 提到 的 rawValue 初始化,是一種隱藏了 init? 的可失敗的 構造器以外,

咱們還能夠自定義 不隱藏的 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後面 加 問號嗎?能夠不加defult 嗎?

答案是 不能夠的

雖然 咱們列舉的case 是 一一俱全的,可是咱們並不能保證 初始化構造的時候 你會傳入什麼東西,因此這個構造是可能會失敗的,結果是可選的,因此就得加 ? ,就須要defult來 處理不存在的 case

 

枚舉的屬性

計算屬性

來,看栗子

吃開封菜的時候到了

經過對 kfc 的點單方式 單點/套餐 咱們寫了一個枚舉,外界經過調用實例的 description 來得到 描述

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

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


k = .Other("漢堡", "可樂", "薯條")
print(k.description) // 今天晚餐吃了漢堡  可樂 還有 薯條
ps: 可樂 漢堡 和薯條 不也是套餐嗎 你個low 狗
複製代碼

咱們定義了一個 KFC 的枚舉

經過 關聯值 + 計算屬性 來 存儲 以及 得到 description

 

小結

  • 由於這裏有關聯值,因此無法經過 rawValue的方式 初始化,也就是說若是經過關聯值初始化,就意味着 獲得的實例 都是存在的,switch 裏 不須要 defult

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

  • 若是說關聯值得個數 不止一個,那麼咱們使用的時候,能夠把修飾 局部變量的let/var 提到 最前面

 

擴展 和協議 的第二種寫法

咱們也能夠 使用協議(Protocols)和協議擴展(Protocol Extension)

高大上 有沒有

經過協議 以及 協議擴展能夠更好的 將 成員值 與 屬性/方法 實現分離開, 代碼也就天然而然的 通俗易懂了

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 "今天我一我的吃了 \(num) 個全家桶"
         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
複製代碼

那麼若是咱們想在方法內改變 自身的值呢?

好比 咱們想中文歌 和 英文歌 來回切換

相似這樣

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

當咱們編譯的時候 就會發現 報錯了

# Cannot assign to value: 'self' is immutable
複製代碼

這個時候咱們就用到 mutating了

mutating

func 前面加上 mutating ,咱們就能夠在值類型中 改變自身的值了

總結

參考連接

SwiftGG

若是有新的知識 我還會補充進來

以上都是我我的的一些見解,可能有不對的地方

都是第一次學Swift ,還請多多指教!!
複製代碼
相關文章
相關標籤/搜索