【Swift學習】Swift編程之旅---枚舉(十二)

  枚舉爲一組相關的值定義一個共同的類型,並容許您在代碼中的以類型安全的方式中使用這些值,在 Swift 中,枚舉類型是一等(first-class)類型。它們採用了不少傳統上只被類所支持的特徵,例如計算型屬性(computed properties),用於提供關於枚舉當前值的附加信息,實例方法(instance methods),用於提供和枚舉所表明的值相關聯的功能。枚舉也能夠定義構造器(initializers)來提供一個初始成員值;能夠在原始的實現基礎上擴展它們的功能;能夠遵照協議(protocols)來提供標準的功能。安全

  

  枚舉語法less

  使用enum關鍵字申明一個枚舉類型,並將整個定義放在大括號內。ide

enum SomeEumeration { 
    // enumeration definition goes here 
} 

 

下面是一個指南針4個主要方向的例子ui

enum CompassPoint { 
    case North 
    case South 
    case East 
    case West 
}

 

枚舉中被定義的值(例如 North,South,East和West)是枚舉的成員值(或者成員)。case關鍵詞申明新的一行成員值將被定義。
 
注意: 不像 C 和 Objective-C 同樣,Swift 的枚舉成員在被建立時不會被賦予一個默認的整數值。在上面的CompassPoints例子中,North,South,East和West不是隱式得等於0,1,2和3。相反的,這些不一樣的枚舉成員在CompassPoint的一種顯示定義中擁有各自不一樣的值。

多個成員能夠出如今同一行上,用逗號隔開編碼

enum Planet { 
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepturn 
} 

每一個枚舉定義了一個全新的類型。像 Swift 中其餘類型同樣,它們的名字(例如CompassPoint和Planet)必須以一個大寫字母開頭。給枚舉類型起一個單數名字而不是複數名字,以便於讀起來更加容易理解spa

var directionToHead = CompassPoint.West

 

directionToHead的類型被推斷當它被CompassPoint的一個可能值初始化。一旦directionToHead被聲明爲一個CompassPoint,你可使用更短的點(.)語法將其設置爲另外一個CompassPoint的值:code

directionToHead = .East

directionToHead的類型已知時,當設定它的值時,你能夠再也不寫類型名。使用顯示類型的枚舉值可讓代碼具備更好的可讀性。blog

 

  使用switch匹配枚舉值字符串

  匹配單個枚舉值it

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") 
} 
// prints "Watch out for penguins」

一個switch語句必須全面。若是忽略了.West這種狀況,上面那段代碼將沒法經過編譯,由於它沒有考慮到CompassPoint的所有成員。全面性的要求確保了枚舉成員不會被意外遺漏。

當不須要匹配每一個枚舉成員的時候,你能夠提供一個默認default分支來涵蓋全部未明確被提出的任何成員

let somePlanet = Planet.Earth 
switch somePlanet { 
case .Earth: 
    println("Mostly harmless") 
default: 
    println("Not a safe place for humans") 
} 
// prints "Mostly harmless」 

 

  關聯值

   Swift 的枚舉能夠存儲任何類型的關聯值,每一個成員的數據類型能夠是各不相同的。枚舉的這種特性跟其餘語言中的可辨識聯合(discriminated unions),標籤聯合(tagged unions),或者變體(variants)類似。

例如,假設一個庫存跟蹤系統須要利用兩種不一樣類型的碼來跟蹤商品。有些商品上標有 UPC-A 格式的條形碼,它使用數字0到9.每個條形碼都有一個表明「數字系統」的數字,該數字後接10個表明「標識符」的數字。最後一個數字是「檢查」位,用來驗證代碼是否被正確掃描:

其餘商品上標有 QR 碼格式的二維碼,它可使用任何 ISO8859-1 字符,而且能夠編碼一個最多擁有2,953字符的字符串:

對於庫存跟蹤系統來講,可以把 UPC-A 碼做爲三個整型值的元組,和把 QR 碼做爲一個任何長度的字符串存儲起來是方便的。

在 Swift 中,用來定義兩種商品條碼的枚舉

enum Barcode { 
    case UPCA(Int, Int, Int) 
    case QRCode(String) 
} 

而後可使用任何一種條碼類型建立新的條碼

var productBarcode = Barcode.UPCA(8, 85909_51226, 3)

以上例子建立了一個名爲productBarcode的新變量,而且賦給它一個Barcode.UPCA的關聯元組值(8, 8590951226, 3)。提供的「標識符」值在整數字中有一個下劃線,使其便於閱讀條形碼。同一個商品能夠被分配給一個不一樣類型的條形碼,

productBarcode = .QRCode("ABCDEFGHIJKLMNOP") 

這時,原始的Barcode.UPCA和其整數值被新的Barcode.QRCode和其字符串值所替代。條形碼的常量和變量能夠存儲一個.UPCA或者一個.QRCode(連同它的關聯值),可是在任何指定時間只能存儲其中之一。

枚舉switch語句

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).") 
} 
// prints "QR code with value of ABCDEFGHIJKLMNOP.」 

 

 

若是一個枚舉成員的全部關聯值被提取爲常量,或者它們所有被提取爲變量,爲了簡潔,你能夠只放置一個var或者let標註在成員名稱前

switch productBarcode { 
case let .UPCA(numberSystem, identifier, check): 
    println("UPC-A with value of \(numberSystem), \(identifier), \(check).") 
case let .QRCode(productCode): 
    println("QR code with value of \(productCode).") 
} 
// prints "QR code with value of ABCDEFGHIJKLMNOP." 

 

  Raw Values

  枚舉成員能夠有初始值,其中這些初始值具備相同的類型,下面是一個枚舉成員存儲原始 ASCII 值的例子

enum ASCIIControlCharacter: Character { 
    case Tab = "\t" 
    case LineFeed = "\n" 
    case CarriageReturn = "\r" 
} 
這裏,稱爲ASCIIControlCharacter的枚舉的原始值類型被定義爲字符型Character,並被設置了一些比較常見的 ASCII 控制字符。字符值的描述請詳見字符串和字符章節。
 
注意,原始值和關聯值是不相同的。當你開始在你的代碼中定義枚舉的時候原始值是被預先填充的值,像上述三個 ASCII 碼。對於一個特定的枚舉成員,它的原始值始終是相同的。關聯值是當你在建立一個基於枚舉成員的新常量或變量時纔會被設置,而且每次當你這麼作得時候,它的值能夠是不一樣的。
 
原始值能夠是字符串,字符,或者任何整型值或浮點型值。每一個原始值在它的枚舉聲明中必須是惟一的。當整型值被用於原始值,若是其餘枚舉成員沒有值時,它們會自動遞增。面的枚舉是對以前Planet這個枚舉的一個細化,利用原始整型值來表示每一個 planet 在太陽系中的順序
enum Planet: Int { 
    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune 
} 

 

自動遞增意味着Planet.Venus的原始值是2,依次類推。
 
使用枚舉成員的toRaw方法能夠訪問該枚舉成員的初始值
let earthsOrder = Planet.Earth.toRaw() 
// earthsOrder is 3 

用枚舉的fromRaw方法來試圖找到具備特定初始值的枚舉成員。這個例子經過初始值7識別Uranus

let possiblePlanet = Planet.fromRaw(7) 
// possiblePlanet is of type Planet? and equals Planet.Uranus 

然而,並不是全部可能的Int值均可以找到一個匹配的行星。正由於如此,fromRaw方法能夠返回一個可選的枚舉成員。在上面的例子中,possiblePlanet是Planet?類型,或「可選的Planet」。若是你試圖尋找一個位置爲9的行星,經過fromRaw返回的可選Planet值將是nil:

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)") 
} 
// prints "There isn't a planet at position 9 

這個範例使用可選綁定(optional binding),經過初始值9試圖訪問一個行星。if let somePlanet = Planet.fromRaw(9)語句得到一個可選Planet,若是可選Planet能夠被得到,把somePlanet設置成該可選Planet的內容。在這個範例中,沒法檢索到位置爲9的行星,因此else分支被執行。

相關文章
相關標籤/搜索