//枚舉
//“枚舉為一組相關(guān)的值定義了一個共同的類型童芹,使你可以在你的代碼中以 類型安全 的方式來使用這些值。
//“在 C 語言中绣版,枚舉會為一組整型值分配相關(guān)聯(lián)的名稱周荐。Swift 中的枚舉更加靈活,不必給每一個枚舉成員提供一個值僵娃。如果給枚舉成員提供一個值(稱為“原始”值)概作,則該值的類型可以是字符串,字符默怨,或是一個整型值或浮點(diǎn)數(shù)”
//“枚舉成員可以指定任意類型的關(guān)聯(lián)值存儲到枚舉成員中讯榕,就像其他語言中的聯(lián)合體(unions)和變體(variants)。你可以在一個枚舉中定義一組相關(guān)的枚舉成員,每一個枚舉成員都可以有適當(dāng)類型的關(guān)聯(lián)值”
//“枚舉類型是一等(first-class)類型愚屁。它們采用了很多在傳統(tǒng)上只被類(class)所支持的特性济竹,例如計算屬性(computed properties),用于提供枚舉值的附加信息霎槐,實(shí)例方法(instance methods)送浊,用于提供和枚舉值相關(guān)聯(lián)的功能。枚舉也可以定義構(gòu)造函數(shù)(initializers)來提供一個初始值丘跌;可以在原始實(shí)現(xiàn)的基礎(chǔ)上擴(kuò)展它們的功能袭景;還可以遵循協(xié)議(protocols)來提供標(biāo)準(zhǔn)的功能
//1.枚舉語法
enum SomeEnumeration{
//枚舉定義放在這里
}
enum CompassPoint{
case north
case south
case east
case west
}
//“枚舉中定義的值(如 north,south闭树,east和west)是這個枚舉的成員值(或成員)耸棒。你可以使用case關(guān)鍵字來定義一個新的枚舉成員值”
//“與 C 和 Objective-C 不同,Swift 的枚舉成員在被創(chuàng)建時不會被賦予一個默認(rèn)的整型值报辱。在上面的CompassPoint例子中与殃,north,south碍现,east和west 不 會被隱式地賦值為0幅疼,1,2和3昼接。相反爽篷,這些枚舉成員本身就是完備的值,這些值的類型是已經(jīng)明確定義好的CompassPoint類型”
//“多個成員值可以出現(xiàn)在同一行上辩棒,用逗號隔開”
enum SomePlanet {
case mercury,Venus,Earth,mars,jupiter,saturn,uranus,neptune
}
//“每個枚舉定義了一個全新的類型狼忱。像 Swift 中其他類型一樣,它們的名字(例如CompassPoint和Planet)應(yīng)該以一個大寫字母開頭”
var directionToHead = CompassPoint.west
//“一旦directionToHead被聲明為CompassPoint類型一睁,你可以使用更簡短的點(diǎn)語法將其設(shè)置為另一個CompassPoint的值:
directionToHead = .east
//2. 使用switch語句匹配枚舉值
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("watch out for penguins")
case .west:
print("Where the skies are blue")
case .east:
print("Where the sun rises")
default:
print("jack")
}
//打印 Watch out for penguins
//3. 關(guān)聯(lián)值
//“可以定義 Swift 枚舉來存儲任意類型的關(guān)聯(lián)值钻弄,如果需要的話,每個枚舉成員的關(guān)聯(lián)值類型可以各不相同者吁。枚舉的這種特性跟其他語言中的可識別聯(lián)合(discriminated unions)窘俺,標(biāo)簽聯(lián)合(tagged unions),或者變體(variants)相似”
enum Barcode {
case upc(Int,Int,Int,Int)
case qrCode(String)
}
//“定義一個名為Barcode的枚舉類型复凳,它的一個成員值是具有(Int瘤泪,Int,Int育八,Int)類型關(guān)聯(lián)值的upc对途,另一個成員值是具有String類型關(guān)聯(lián)值的qrCode”
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
//“創(chuàng)建了一個名為productBarcode的變量,并將Barcode.upc賦值給它髓棋,關(guān)聯(lián)的元組值為(8, 85909, 51226, 3)”
productBarcode = .qrCode("ABCDEFGHIJK")
//“同一個商品可以被分配一個不同類型的條形碼, 這時实檀,原始的Barcode.upc和其整數(shù)關(guān)聯(lián)值被新的Barcode.qrCode和其字符串關(guān)聯(lián)值所替代惶洲。Barcode類型的常量和變量可以存儲一個.upc或者一個.qrCode(連同它們的關(guān)聯(lián)值),但是在同一時間只能存儲這兩個值中的一個”
//“你可以在switch的 case 分支代碼中提取每個關(guān)聯(lián)值作為一個常量(用let前綴)或者作為一個變量(用var前綴)來使用”
switch productBarcode {
case .upc(let numberSystem,let manufacturer,let product,let check):
print("UPC: \(numberSystem),\(manufacturer),\(product),\(check)")
case .qrCode(let productCode):
print("QRCode: \(productCode)")
}
// 打印QRCode:ABCDEFGHIJK
//如果一個枚舉成員的所有關(guān)聯(lián)值都被提取為常量或者變量膳犹,可以只在成員名稱前標(biāo)注一個let或者var
switch productBarcode {
case let .upc(numberSystem,manufacturer,product,check) :
print("upc:\(numberSystem),\(manufacturer),\(product),\(check)")
case let .qrCode(procuctCode):
print("qrcode \(procuctCode)")
}
//打印qrcode ABCDEFGHIJK
//4.原始值
//“作為關(guān)聯(lián)值的替代選擇恬吕,枚舉成員可以被默認(rèn)值(稱為原始值)預(yù)填充,這些原始值的類型必須相同”
enum ASCIIControlCharacter: Character{
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
//“原始值可以是字符串须床,字符铐料,或者任意整型值或浮點(diǎn)型值。每個原始值在枚舉聲明中必須是唯一的”
//3.1原始值的隱式賦值
//“在使用原始值為整數(shù)或者字符串類型的枚舉時豺旬,不需要顯式地為每一個枚舉成員設(shè)置原始值钠惩,Swift 將會自動為你賦值”
//“當(dāng)使用整數(shù)作為原始值時,隱式賦值的值依次遞增1哈垢。如果第一個枚舉成員沒有設(shè)置原始值妻柒,其原始值將為0”
enum Planet : Int{
case mercury = 1 ,venus, earth, mars,jupiter,saturn,uranus,neptune
}
//“Plant.mercury的顯式原始值為1扛拨,Planet.venus的隱式原始值為2耘分,依次類推
//“當(dāng)使用字符串作為枚舉類型的原始值時,每個枚舉成員的隱式原始值為該枚舉成員的名稱”
enum SomeCompassPoint : String{
case north ,south ,east , west
}
//“SomeCompassPoint.south擁有隱式原始值south绑警,依次類推
//“rawValue屬性可以訪問該枚舉成員的原始值”
let earthsOrder = Planet.earth.rawValue
//earthsOrder 值為3
let sunsetDirection = SomeCompassPoint.west.rawValue
//sunsetDirection 值為 "west"
//3.2 “使用原始值初始化枚舉實(shí)例”
//“如果在定義枚舉類型的時候使用了原始值求泰,那么將會自動獲得一個初始化方法,這個方法接收一個叫做rawValue的參數(shù)计盒,參數(shù)類型即為原始值類型渴频,返回值則“是枚舉成員或nil。你可以使用這個初始化方法來創(chuàng)建一個新的枚舉實(shí)例
let possiblePlanet = Planet(rawValue:7)
//possiblePlanet 類型為 Plant北启? 值為Plant.uranus
//“并非所有Int值都可以找到一個匹配的行星卜朗。因此,原始值構(gòu)造器總是返回一個可選的枚舉成員咕村。在上面的例子中场钉,possiblePlanet是Planet?類型,或者說“可選的Planet”
let positionToFind = 11
if let somePlant = Planet(rawValue:positionToFind) {
switch somePlant {
case .earth:
print("Mostly harmless")
default:
print("not a safe place for humans")
}
}else{
print("there isn't a planet at position \(positionToFind)") //輸出
}
//“這個例子使用了可選綁定(optional binding)懈涛,試圖通過原始值11來訪問一個行星逛万。if let somePlanet = Planet(rawValue: 11)語句創(chuàng)建了一個可選Planet,如果可選Planet的值存在批钠,就會賦值給somePlanet宇植。在這個例子中,無法檢索到位置為11的行星埋心,所以else分支被執(zhí)行”
//4.遞歸枚舉
//“遞歸枚舉是一種枚舉類型指郁,它有一個或多個枚舉成員使用該枚舉類型的實(shí)例作為關(guān)聯(lián)值。使用遞歸枚舉時拷呆,編譯器會插入一個間接層闲坎。你可以在枚舉成員前加上indirect來表示該成員可遞歸”
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression,ArithmeticExpression)
indirect case multiplication(ArithmeticExpression,ArithmeticExpression)
}
//“你也可以在枚舉類型開頭加上indirect關(guān)鍵字來表明它的所有成員都是可遞歸的”
indirect enum AnotherArithmeticExpression{
case number(Int)
case addition(AnotherArithmeticExpression,AnotherArithmeticExpression)
case mutiplication(AnotherArithmeticExpression,AnotherArithmeticExpression)
}
//“定義的枚舉類型可以存儲三種算術(shù)表達(dá)式:純數(shù)字、兩個表達(dá)式相加、兩個表達(dá)式相乘箫柳。枚舉成員addition和multiplication的關(guān)聯(lián)值也是算術(shù)表達(dá)式——這些關(guān)聯(lián)值使得嵌套表達(dá)式成為可能手形。例如,表達(dá)式(5 + 4) * 2悯恍,乘號右邊是一個數(shù)字库糠,左邊則是另一個表達(dá)式。因?yàn)閿?shù)據(jù)是嵌套的涮毫,因而用來存儲數(shù)據(jù)的枚舉類型也需要支持這種嵌套——這意味著枚舉類型需要支持遞歸瞬欧。下面的代碼展示了使用ArithmeticExpression這個遞歸枚舉創(chuàng)建表達(dá)式(5 + 4) * 2”
let five = AnotherArithmeticExpression.number(5)
let four = AnotherArithmeticExpression.number(4)
let sum = AnotherArithmeticExpression.addition(five, four)
let product = AnotherArithmeticExpression.mutiplication(sum,AnotherArithmeticExpression.number(2))
//“要操作具有遞歸性質(zhì)的數(shù)據(jù)結(jié)構(gòu),使用遞歸函數(shù)是一種直截了當(dāng)?shù)姆绞桨辗馈@缢一ⅲ旅媸且粋€對算術(shù)表達(dá)式求值的函數(shù)”
func evaluate(_ expression: AnotherArithmeticExpression) ->Int{
switch expression {
case let .number(value) :
return value
case let .addition(left,right) :
return evaluate(left) + evaluate(right) //遞歸
case let .mutiplication(left,right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
//打印18