枚舉入門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
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 來初始化
如
enum Drinking: String {
case cola
case sprite
case orangeJuice
}
var dg = Drinking(rawValue: "cola")
# 注意: 這裏的dg 是可選型,由於 枚舉並不知道 你傳進去的 rawValue 是否存在
# 下面會說到,這種方式的實例化 是一個可失敗的構造器
複製代碼
通常來講,咱們寫出枚舉 是爲了區分不一樣的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(可選型) 是比較經常使用的枚舉,它的成員值 .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 初始化
,是一種隱藏了 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
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了
在func 前面加上 mutating
,咱們就能夠在值類型中 改變自身的值了
參考連接
若是有新的知識 我還會補充進來
以上都是我我的的一些見解,可能有不對的地方
都是第一次學Swift ,還請多多指教!!
複製代碼