枚舉
使用enum關鍵詞來創(chuàng)建枚舉并且把它們的整個定義放在一對大括號內(nèi):
enum SomeEnumeration {
// 枚舉定義放在這里
}
下面是用枚舉表示指南針四個方向的例子:
enum CompassPoint {
case North
case South
case East
case West
}”
var directionToHead=CompassPoint.West
//當directionToHead的類型已知時,再次為其賦值可以省略枚舉類型名
directionToHead=.East
枚舉中定義的值(如 North侥涵,South,East和West)是這個枚舉的成員值(或成員)渔隶。你使用case關鍵字來定義一個新的枚舉成員值寸认。
“與 C 和 Objective-C 不同,Swift 的枚舉成員在被創(chuàng)建時不會被賦予一個默認的整型值敬鬓。在上面的CompassPoint例子中淹朋,North,South钉答,East和West不會被隱式地賦值為0础芍,1,2和3数尿。相反仑性,這些枚舉成員本身就是完備的值,這些值的類型是已經(jīng)明確定義好的CompassPoint類型右蹦≌锔耍”
你可以使用switch語句匹配單個枚舉值:
directionToHead = .South
switch directionToHead {
case .North:
print("Lots of planets have a north")
case .South:
print("Watch out for penguins")
case .East:
print("Where the sun rises")
case .West:
print("Where the skies are blue")
}
// 輸出 "Watch out for penguins”
當不需要匹配每個枚舉成員的時候,你可以提供一個default分支來涵蓋所有未明確處理的枚舉成員:
let somePlanet = Planet.Earth
switch somePlanet {
case .Earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// 輸出 "Mostly harmless”
關聯(lián)值
你可以定義 Swift 枚舉來存儲任意類型的關聯(lián)值何陆,如果需要的話晨汹,每個枚舉成員的關聯(lián)值類型可以各不相同。枚舉的這種特性跟其他語言中的可識別聯(lián)合(discriminated unions)甲献,標簽聯(lián)合(tagged unions)宰缤,或者變體(variants)相似。
如下代碼:
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
//“原始的Barcode.UPCA和其整數(shù)關聯(lián)值被新的Barcode.QRCode和其字符串關聯(lián)值所替代”
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
以上代碼可以這么理解:
“定義一個名為Barcode的枚舉類型晃洒,它的一個成員值是具有(Int慨灭,Int,Int球及,Int)類型關聯(lián)值的UPCA氧骤,另一個成員值是具有String類型關聯(lián)值的QRCode。創(chuàng)建了一個名為productBarcode的變量吃引,并將Barcode.UPCA賦值給它筹陵,關聯(lián)的元組值為(8, 85909, 51226, 3)刽锤。”
可以使用一個 switch 語句來檢查不同的條形碼類型朦佩。然而并思,這一次,關聯(lián)值可以被提取出來作為 switch 語句的一部分语稠。你可以在switch的 case 分支代碼中提取每個關聯(lián)值作為一個常量(用let前綴)或者作為一個變量(用var前綴)來使用:
switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
print("QR code: \(productCode).")
}
// 輸出 "QR code: ABCDEFGHIJKLMNOP."
如果一個枚舉成員的所有關聯(lián)值都被提取為常量宋彼,或者都被提取為變量,為了簡潔仙畦,你可以只在成員名稱前標注一個let或者var:
switch productBarcode {
case let .UPCA(numberSystem, manufacturer, product, check):
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .QRCode(productCode):
print("QR code: \(productCode).")
}
// 輸出 "QR code: ABCDEFGHIJKLMNOP."
原始值
作為關聯(lián)值的替代選擇输涕,枚舉成員可以被默認值(稱為原始值)預填充,這些原始值的類型必須相同慨畸。
這是一個使用 ASCII 碼作為原始值的枚舉:
//“枚舉類型ASCIIControlCharacter的原始值類型被定義為Character莱坎,并設置了一些比較常見的 ASCII 控制字符”
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
原始值可以是字符串,字符寸士,或者任意整型值或浮點型值檐什。每個原始值在枚舉聲明中必須是唯一的。
注意:原始值和關聯(lián)值是不同的碉京。原始值是在定義枚舉時被預先填充的值厢汹,像上述三個 ASCII 碼。對于一個特定的枚舉成員谐宙,它的原始值始終不變烫葬。關聯(lián)值是創(chuàng)建一個基于枚舉成員的常量或變量時才設置的值,枚舉成員的關聯(lián)值可以變化凡蜻。
原始值得隱式賦值
代碼如下:
// Plant.Mercury的顯式原始值為1搭综,Planet.Venus的隱式原始值為2,依次類推
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
當使用字符串作為枚舉類型的原始值時划栓,每個枚舉成員的隱式原始值為該枚舉成員的名稱兑巾。
下面的例子是CompassPoint枚舉的細化,使用字符串類型的原始值來表示各個方向的名稱:
enum CompassPoint: String {
case North, South, East, West
}
上面例子中忠荞,CompassPoint.South擁有隱式原始值South蒋歌,依次類推。
使用枚舉成員的rawValue屬性可以訪問該枚舉成員的原始值:
let earthsOrder = Planet.Earth.rawValue
// earthsOrder 值為 3
let sunsetDirection = CompassPoint.West.rawValue
// sunsetDirection 值為 "West”
使用原始值初始化枚舉實例
這個例子利用原始值7創(chuàng)建了枚舉成員Uranus:
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet 類型為 Planet? 值為 Planet.Uranus
注意:
原始值構造器是一個可失敗構造器委煤,因為并不是每一個原始值都有與之對應的枚舉成員堂油。更多信息請參見可失敗構造器
let positionToFind = 9
if let somePlanet = Planet(rawValue: positionToFind) {
switch somePlanet {
case .Earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("There isn't a planet at position \(positionToFind)")
}
// 輸出 "There isn't a planet at position 9
這個例子使用了可選綁定(optional binding),試圖通過原始值9來訪問一個行星碧绞。if let somePlanet = Planet(rawValue: 9)語句創(chuàng)建了一個可選Planet府框,如果可選Planet的值存在,就會賦值給somePlanet讥邻。在這個例子中迫靖,無法檢索到位置為9的行星院峡,所以else分支被執(zhí)行。
遞歸枚舉
以下是難懂的術語解釋:
“遞歸枚舉(recursive enumeration)是一種枚舉類型系宜,它有一個或多個枚舉成員使用該枚舉類型的實例作為關聯(lián)值照激。使用遞歸枚舉時,編譯器會插入一個間接層蜈首。你可以在枚舉成員前加上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)
}
要操作具有遞歸性質(zhì)的數(shù)據(jù)結構赏淌,使用遞歸函數(shù)是一種直截了當?shù)姆绞讲瓤堋@纾旅媸且粋€對算術表達式求值的函數(shù):
func evaluate(expression: ArithmeticExpression) -> Int {
switch expression {
case .Number(let value):
return value
case .Addition(let left, let right):
return evaluate(left) + evaluate(right)
case .Multiplication(let left, let right):
return evaluate(left) * evaluate(right)
}
}
// 計算 (5 + 4) * 2
let five = ArithmeticExpression.Number(5)
let four = ArithmeticExpression.Number(4)
let sum = ArithmeticExpression.Addition(five, four)
let product = ArithmeticExpression.Multiplication(sum, ArithmeticExpression.Number(2))
print(evaluate(product))
// 輸出 "18"
該函數(shù)如果遇到純數(shù)字六水,就直接返回該數(shù)字的值俺孙。如果遇到的是加法或乘法運算,則分別計算左邊表達式和右邊表達式的值掷贾,然后相加或相乘睛榄。