詳解Swift中enum枚舉類型的用法
一、引言
在Objective-C語言中,沒有實際上是整型數(shù)據(jù),Swift中的枚舉則更加靈活,開發(fā)者可以不為其分配值類型把枚舉作為獨立的類型來使用,也可以為其分配值,可以是字符,字符串,整型或者浮點型數(shù)據(jù)。
二、枚舉語法
Swift中enum關(guān)鍵字來進行枚舉的創(chuàng)建,使用case來創(chuàng)建每一個枚舉值,示例如下:
//創(chuàng)建姓氏枚舉,和Objective-C不同,Swift枚舉不會默認分配值 enum Surname { case 張 case 王 case 李 case 趙 } //創(chuàng)建一個枚舉類型的變量 var myName = Surname.張 //如果可以自動推斷出類型 則枚舉類型可以省略 myName = .李 var myName2:Surname = .王
enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
switch myName { case .張: print("姓氏張") case .王: print("姓氏王") case .李: print("姓氏李") case .趙: print("姓氏趙") }
Swift中的枚舉有一個很有意思的特點,其可以設(shè)置一些相關(guān)值,通過相關(guān)值,開發(fā)者可以從公用的枚舉值中獲取到傳遞的額外相關(guān)值,示例如下:
enum Number { case one(count:Int) case two(count:Int) case three(count:Int) case four(count:Int) } var num = Number.one(count: 5) switch num { //獲取num的相關(guān)值 case Number.one(let count): print(count) default: print(num) } //如果一個枚舉值所有的相關(guān)中都是常量,let關(guān)鍵字也可以提取到括號外面 switch num { //獲取num的相關(guān)值 case let Number.one(count): print(count) default: print(num) }
有了相關(guān)值這樣的句法,大大的增加了枚舉的靈活性,例如一個形狀枚舉,可能的枚舉值有矩形,圓形等,矩形的枚舉值就可以提供寬高的相關(guān)值,圓形的枚舉值就可以提供半徑的相關(guān)值,是開發(fā)更加靈活。
四、枚舉的原始值
原始值也可以理解為為枚舉設(shè)置一個具體類型,示例如下:
enum Char:String { case a = "A" case b = "B" case c = "C" } //”A“ var char = Char.a.rawValue
注意,如果枚舉是Int類型的,則類似于Objective-C,枚舉的原始值會從第一個開始之后依次遞增:
enum Char:Int{ case a = 0 case b case c } //1 var char = Char.b.rawValue
同樣可以通過原始值的方式來進行枚舉對象的創(chuàng)建,示例如下:
enum Char:Int{ case a = 0 case b case c } //1 var char = Char.b.rawValue //b var char2 = Char(rawValue:1)
在通過原始值進行枚舉對象創(chuàng)建的時候,有可能創(chuàng)建失敗,例如傳入的原始值并不存在,這時會返回Optional值nil。
四、遞歸枚舉
遞歸枚舉是Swift枚舉中一個難于理解的地方,實際上也并非十分難于理解,開發(fā)者只要明白枚舉的實質(zhì),遞歸枚舉就很好理解。首先,遞歸是一種算法,可以簡單理解為自己調(diào)用自己,而枚舉實際上并不是函數(shù),它并不執(zhí)行某項運算,它只是表達一個數(shù)據(jù)或者說他也可以表達一種表達式,示例如下:
enum Expression { //表示加 case add //表示減 case mul }
前面有提到過相關(guān)值的概念,因此,對于上述例子,可以為add和mul枚舉值添加兩個相關(guān)值作為參數(shù)。
enum Expression { //表示加 case add(Int,Int) //表示減 case mul(Int,Int) }
如此,如下的寫法實際上就可以代表一個5+5的表達式:
var exp = Expression.add(5, 5)
還是需要強調(diào)一點,這個exp只是表達了5+5這樣一個約定的表達式,它并沒有真正進行5+5的運算。現(xiàn)在問題就來了,使用如上的枚舉,怎樣來表達類似(5+5)*5這樣的復合表達式呢?可以使用遞歸枚舉來實現(xiàn),即將(5+5)作為枚舉值得相關(guān)值再次創(chuàng)建枚舉,改造如下:
enum Expression { //單值數(shù)據(jù) case num(Int) //表示加 indirect為遞歸枚舉關(guān)鍵字 indirect case add(Expression,Expression) //表示減 indirect case mul(Expression,Expression) } var exp1 = Expression.num(5) var exp2 = Expression.num(5) var exp3 = Expression.add(exp1, exp2) var exp4 = Expression.mul(exp1, exp3)
上面exp4實際上就表達了(5+5)*5這樣一個過程,注意遞歸的枚舉值必須加上indirect關(guān)鍵字來聲明。處理遞歸枚舉最好的方式是通過遞歸函數(shù),示例如下:
func expFunc(param:Expression) -> Int { //進行枚舉判斷 switch param { //如果是單獨數(shù)字 直接返回 case .num(let p): return p //如果是加法 則進行遞歸加 case .add(let one, let two): return expFunc(one)+expFunc(two) //如果是乘法 則進行遞歸乘 case .mul(let one, let two): return expFunc(one)*expFunc(two) } } //50 expFunc(exp4)
如果枚舉中所有的case都是可遞歸的,可以將整個枚舉聲明為可遞歸的:
indirect enum Expression { //單值數(shù)據(jù) case num(Int) //表示加 indirect為遞歸枚舉關(guān)鍵字 case add(Expression,Expression) //表示減 case mul(Expression,Expression) }
五、一些重點難點總結(jié)
枚舉的語法,enum開頭,每一行成員的定義使用case關(guān)鍵字開頭,一行可以定義多個關(guān)鍵字
enum CompassPoint { case North case South case East case West } enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
上例中North,South,East,West的值并不等于0,1,2,3,而是他們本身就是自己的值,且該值的類型就是CompassPoint
var directionToHead = CompassPoint.West //directionToHead是一個CompassPoint類型,可以被賦值為該類型的其他值 //當設(shè)置directionToHead的值時,他的類型是已知的,因此可以省略East的類型 directionToHead = .East
使用switch分開枚舉的值,以進行的不同的操作。switch內(nèi)的case必須包含枚舉的所有分支,否則編譯出錯。當然,列舉所有枚舉值不太方便時,可以使用default
directionToHead = .South switch directionToHead { case .North: println("Lots of planets have a north") case .South: println("Watch out for penguins") case .East: println("Where the sun rises") case .West: println("Where the skies are blue") } // 打印 "Watch out for penguins"
枚舉的元素可以是結(jié)合值(associated value),下面通過一個可以存儲一維條形碼(由3個整數(shù)組成)和二維條形碼(由字符串組成)的枚舉條形碼實例來說明
enum Barcode { case UPCA(Int, Int, Int) case QRCode(String) } //定義一個變量。該變量即可被賦值為3個整數(shù),又可被賦值為一個字符串,但都是Barcode類型的枚舉值 var productBarcode = Barcode.UPCA(8, 85909_51226, 3) productBarcode = .QRCode("ABCDEFGHIJKLMNOP") //使用switch時,case內(nèi)可區(qū)分條形碼種類,可使用變量或常量獲得結(jié)合值 switch productBarcode { case .UPCA(let numberSystem, let identifier, let check): println("UPC-A with value of \(numberSystem), \(identifier), \(check).") case .QRCode(let productCode): println("QR code with value of \(productCode).") } // 打印 "QR code with value of ABCDEFGHIJKLMNOP."
在case內(nèi)部,如果其類型都為let或var,則該關(guān)鍵字可提前到case和枚舉類型中間,如:
case let .UPCA(numberSystem, identifier, check):
原始值類型的枚舉在枚舉名后緊跟數(shù)據(jù)類型,其枚舉的成員在定義時已經(jīng)賦予了初始值,且不能改變,與結(jié)合值類型的枚舉相比,結(jié)合值是在將枚舉值賦予一個變量時,才設(shè)置了那個枚舉的值。
原始值枚舉更像C語言的枚舉,比如整數(shù)型的原始值枚舉,其成員的值如果未指定,則是遞增的。
原始值枚舉也像字典類型,并且是雙向字典,因為他既可以通過枚舉成員獲得該成員原始值,又可以通過原始值,獲得枚舉成員。由此也可以見得,這種枚舉的原始值是不能出現(xiàn)相同值的
//原始值枚舉的類型緊跟枚舉名后,其成員的原始值的數(shù)據(jù)類型都是這個指定的類型 enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" case CarriageReturn = "\r" } //Int類型的原始值枚舉成員的原始值是遞增的,比如Venus的值是2,Earth的值是3 enum Planet: Int { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune } //可以通過toRaw方法獲得枚舉成員的原始值 let earthsOrder = Planet.Earth.toRaw() // earthsOrder 的值是 3,數(shù)據(jù)類型是Int //可以通過fromRaw方法獲得原始值對應的枚舉成員 let possiblePlanet = Planet.fromRaw(7) // possiblePlanet 的數(shù)據(jù)類型 Planet? 值是 Planet.Uranus //因為fromRaw的原始值可能沒有對應的枚舉成員,所以返回的類型是一個可選變量值 let positionToFind = 9 if let somePlanet = Planet.fromRaw(positionToFind) { switch somePlanet { case .Earth: println("Mostly harmless") default: println("Not a safe place for humans") } } else { println("There isn't a planet at position \(positionToFind)") } // 枚舉定義中沒有原始值為9的成員,所以打印 "There isn't a planet at position 9"
相關(guān)文章
淺談Swift編程中switch與fallthrough語句的使用
這篇文章主要介紹了Swift編程中switch與fallthrough語句的使用,用于基本的流程控制,需要的朋友可以參考下2015-11-11