Swift 5.1 (8) - 枚舉類型

級別: ★☆☆☆☆
標簽:「iOS」「Swift 5.1」「枚舉」「迭代枚舉」「枚舉關聯值」「遞歸枚舉」
作者: 沐靈洛
審校: QiShare團隊


Enumeration:枚舉類型

一個枚舉類型是為一組相關聯的值定義的一個公共類型,使得這些關聯值能夠在代碼中以類型安全的方式進行處理。
C語言中的枚舉類型將相關的枚舉項使用整數值表示。而Swift中的枚舉更靈活,并且沒有為枚舉項提供值。如果為為枚舉項提供值(則該值稱為原始值raw value),該值可以是字符串,字符,任何整數或浮點類型的值。
另外,枚舉項可以指定任何類型的關聯值與枚舉項的值一起存儲。我們可以定義一組通用的相關項作為枚舉的一部分,每個枚舉都有一組比較合適的類型的不同值與之關聯。同時Swift中的枚舉類型采用了許多只有類才支持的特征,比如枚舉:

  • 能夠提供計算屬性,用于支持枚舉當前值之外的額外的信息;
  • 能夠提供實例方法,用于支持與枚舉所代表的值相關的功能;
  • 能夠定義初始化方法,提供初始枚舉項的值;
  • 能夠支持擴展, 可以在原始實現的基礎上擴展其功能;
  • 能夠遵守協議,用于提供一切標準的功能;

枚舉語法

使用enum關鍵字引入枚舉,并將其整個定義放在{}

enum <#name#> {
    case <#case#>
}

枚舉的定義與使用

enum CompassPoint {
    case north
    case west
    case east
    case south
}
//多個枚舉寫在一行中。
enum CompassPoint {
    case north,west,east,south
}

每個枚舉定義都定義了一個新類型。

var direction : CompassPoint = .north
var direction = CompassPoint.north

使用Switch語句匹配枚舉值

let direction : CompassPoint = .north
switch direction {
case .east:
    print("ease")
case .north:
    print("north")
case .west:
    print("west")
case .south:
    print("south")
}

迭代枚舉項

通過在枚舉名稱后使用: CaseIterable,可以使枚舉,擁有一個關于所有枚舉項的集合。調用枚舉類型的allCases屬性,可以獲取這個集合。

enum CompassPoint : CaseIterable{
    case north,west,east,south
}
//輸出allCases
/*
 log:[swift_basic.EnumerationPractice.CompassPoint.north, swift_basic.EnumerationPractice.CompassPoint.west, swift_basic.EnumerationPractice.CompassPoint.east, swift_basic.EnumerationPractice.CompassPoint.south]
 */
print(CompassPoint.allCases)
switch CompassPoint.allCases.first! {
case .north:
    print("輸出正確")
default:
    print("輸出失敗")
}
//eachCase每一項都是枚舉類型的示例
for eachCase in CompassPoint.allCases {
    /*north
     west
     east
     south*/
    print(eachCase)
}

枚舉關聯值

枚舉類型中在枚舉項的旁邊存貯額外的其他類型的值,這些值被稱為關聯值。并且每次在代碼中使用有關聯值的枚舉項時,該關聯值都會有所不同。
Swift中可以定義枚舉以存儲任何給定類型的關聯值,并且每個枚舉項的值類型也可以不同。
例如:商品碼有二維碼和條形碼兩種形式。二維碼的信息可以提取為String類型,條形碼的信息是一串數字,按照:一位系統數字+五位制造商標識+五位產品標識+一位校驗數字的格式,我們可以聯想到(Int,Int,Int,Int)元組類型。所以我們使用關聯值定義枚舉類型如下: 通用商品條碼

enum ProductCode {
    case upc(Int,Int,Int,Int)//通用商品條碼
    case qrCode(String)//二維碼
}

上述代碼解讀:定義了一個枚舉類型ProductCode,有兩個枚舉項upcqrCode。這兩個枚舉項分別可以存儲(Int, Int, Int, Int)類型和String類型的關聯值。
ProductCode枚舉類型的定義不提供任何實際意義的IntString值。 它只定義ProductCode常量和變量在等于ProductCode.upcProductCode.qrCode時可以存儲的關聯值的類型。

var productCode = ProductCode.upc(1, 22, 333, 4444)
productCode = ProductCode.qrCode("二維碼哈")

使用Switch語句匹配枚舉項并且提取枚舉項的關聯值??梢允褂?code>let和var將每個關聯值提取為常量或變量,以在case的正文中使用。

var productCode = ProductCode.upc(1, 22, 333, 4444)
switch productCode {
case .upc(let x, let y, let z, let zz):
    print("從switch語句中提取的相匹配的枚舉項的關聯值為x:\(x) y:\(y) z:\(z) zz:\(zz)")
case ProductCode.qrCode(let str):
    print("從switch語句中提取的相匹配的枚舉項的關聯值為:\(str)")
}
productCode = ProductCode.qrCode("二維碼哈")
switch productCode {
case let .upc(x, y, z, zz):
    print("從switch語句中提取的相匹配的枚舉項的關聯值為x:\(x) y:\(y) z:\(z) zz:\(zz)")
case let .qrCode(str):
    print("從switch語句中提取的相匹配的枚舉項的關聯值為:\(str)")
}

枚舉原始值

關聯值的示例中展示了枚舉如何聲明它們存儲不同類型的關聯值。作為關聯值的替代,枚舉也可以預先填充默認值(稱為原始值),它們都是相同的類型。

enum NameType : String{
    case ZhangFei = "張飛"
    case GuanYu = "關羽"
    case LiuBei = "劉備"
}
let name = NameType.ZhangFei
print(name.rawValue)//!< log:張飛

枚舉NameType的原始值被定義為String類型,并被設置原始值。原始值可以是字符串,字符或任何整數或浮點數類型。每個原始值在其枚舉聲明中必須是唯一的。
原始值與關聯值不同。原始值:預先填充的默認值,對于特定的枚舉項,其原始值總是相同的。關聯值:每次基于枚舉情況之一創建一個常量或變量時,其關聯值可以是不同的。
隱式分配原始值
使用原始值為整數或字符串類型的枚舉時,可以不用為每個case顯式分配原始值。因為Swift會自動為我們分配值。例如,當整數用于原始值時,每種情況的隱含值比前一種情況多一個。如果第一種情況沒有設置值,則其值為0??梢允褂?code>rawValue屬性訪問枚舉項的原始值。

enum Planet: Int,CaseIterable {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
//查看各項的`rawvalue`
var planetOutStr = "枚舉類型Planet各項的原始值"
for item in Planet.allCases {
    planetOutStr += "\(item) : \(item.rawValue) "
}
print(planetOutStr)//!< 枚舉類型Planet各項的原始值mercury : 1 venus : 2 earth : 3 mars : 4 jupiter : 5 saturn : 6 uranus : 7 neptune : 8

原始值為字符串類型的枚舉,每個枚舉項隱式分配的原始值是該枚舉項的名稱。

enum CompassPoint :String,CaseIterable{
    case north,west,east,south
}
var directionOutStr = "枚舉類型CompassPoint各項的原始值"
for item in CompassPoint.allCases {
    directionOutStr += "\(item) : '\(item.rawValue)' "
}
print(directionOutStr)//!< 枚舉類型CompassPoint各項的原始值north : 'north' west : 'west' east : 'east' south : 'south' 

從原始值初始化
如果使用原始值類型定義枚舉,則枚舉會自動接收一個參數名:rawValue參數類型:原始值類型的初始話方法,并返回枚舉項或nil。我們可以使用此初始化方法嘗試創建該枚舉類型的新實例。

let possiblePalnet = Planet.init(rawValue: 7)
//!< Planet類型的可選項。Optional(swift_basic.EnumerationPractice.Planet.uranus)
//無法根據原始值匹配到枚舉項的情況
let possiblePalnet = Planet.init(rawValue: 9)//!< Planet類型的可選項。9已經超出了枚舉的所有項的范圍。log:nil
//需要解包,可選綁定
if let possiblePlanet = possiblePalnet {
    print(possiblePlanet)
    switch possiblePlanet {
    case .earth:
        print("地球")
    default:
        print("其他行星")
    }
} else {
    print("沒有找到合適的枚舉項")
}

枚舉的遞歸

定義一個枚舉時,若該枚舉類型的某個case關聯了一個或多個該枚舉類型的值時,系統會自動提示,需要添加indirect關鍵字,因為此時的枚舉類型已經被定義為了擁有遞歸結構的遞歸枚舉。通過在枚舉項的前面使用indirect關鍵字,來表示此枚舉項是可遞歸的。
以下示例為存儲了三個數學表達式遞歸枚舉的定義。

//方式一
//遞歸枚舉,存儲了三個數學表達式 使用`indirect`來表示枚舉項時可遞歸調用的。
enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

在枚舉開始之前使用indirect關鍵字,為具有關聯值的所有枚舉項啟用遞歸:

//方式二
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

ArithmeticExpression枚舉類型的每一項都設置有相應的關聯值,并且additionmultiplication都關聯了可以存儲(ArithmeticExpression, ArithmeticExpression)類型的值。即:分別關聯了兩個ArithmeticExpression枚舉類型。

遞歸枚舉的嵌套:

//存儲了一個為5的關聯值
let five = ArithmeticExpression.number(5)
//存儲了一個為6的關聯值
let six = ArithmeticExpression.number(6)
//存儲了一個為3的關聯值
let three = ArithmeticExpression.number(3)
//addition枚舉項,關聯了兩個當前枚舉類型的值。
let sum = ArithmeticExpression.addition(five, six)
//multiplication枚舉項,關聯了兩個當前枚舉類型的值。
let multiplication = ArithmeticExpression.multiplication(sum, three)//數學表達式的呈現形式。

創建遞歸函數驗證multiplication是否可以計算正確結果

//創建一個遞歸函數驗證可遞歸性
func arithmeticOperation(_ expression : ArithmeticExpression) -> Int {
    
    switch expression {
    case let .number(x):
        return x
    case let .addition(x, y):
        //! 此處x和y仍舊是表達式,所以需要先進行遞歸運算得出`Int`類型的關聯值
        return arithmeticOperation(x) + arithmeticOperation(y)
    case .multiplication(let x, let y):
        //! 此處x和y仍舊是`ArithmeticExpression`,所以需要先進行遞歸運算得出`Int`類型的關聯值
        return arithmeticOperation(x) * arithmeticOperation(y)
    }
}
print("嵌套的數學表達式進行遞歸調用后的結果是:\(arithmeticOperation(multiplication))")
//!< log:嵌套的數學表達式進行遞歸調用后的結果是:33

參考資料:
swift 5.1官方編程指南


推薦文章:
iOS 給UILabel添加點擊事件
用SwiftUI給視圖添加動畫
用SwiftUI寫一個簡單頁面
Swift 5.1 (7) - 閉包
iOS App啟動優化(三)—— 自己做一個工具監控App的啟動耗時
iOS App啟動優化(二)—— 使用“Time Profiler”工具監控App的啟動耗時
iOS App啟動優化(一)—— 了解App的啟動流程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容