1. 程式人生 > >swift_031(Swift 中的列舉/原始值(RawValues))

swift_031(Swift 中的列舉/原始值(RawValues))

列舉定義語法

首先,我們來看看在 swift 中定義列舉的語法:

enum WeekDay {

    case Monday
    case Tuesday
    case Wednesday
    case Thursday
    case Friday
    case Saturday
    case Sunday

}

我們注意到,swift 的每個列舉項前面,都使用一個 case 關鍵字來標識。除了每行宣告一個列舉項,也可以將這些列舉項放在一行中宣告,每項之間用逗號分隔。

enum WeekDayInSingleLine {

    case Monday,Tuesday
,Wednesday,Thursday,Friday,Saturday,Sunday }

注意一點,Objective-C 和 C 語言那樣, swift 中的列舉項不可以用 0,1,2 這樣的數字值來代替。它們有自己的值。

列舉型別定義好之後,我們就可以將它的列舉值賦值給某個變數:

var weekday = WeekDay.Tuesday

並且,對於型別明確的變數,我們可以直接省去列舉的型別字首:

var day:WeekDay = .Wednesday

列舉的使用

列舉值可以在 switch 語句中進行匹配:

switch weekday {

case .Monday:
    println
(":(") case .Tuesday: println(":(") case .Wednesday: println(":(") case .Thursday: println(":(") case .Friday: println(":|") case .Saturday: println(":)") case .Sunday: println(":)") }

switch 語句中的每個 case 中,我們提供各個列舉項的名稱:.Monday,.Tuesday 等等。在 swift 中 switch 中匹配列舉項,必須顯示的列舉出所有的列舉項。也就是對於我們上面表示星期的列舉型別WeekDay

, 我們對它的 switch 語句中必須將所有的列舉項分支都明確的寫出來。否則就會有編譯錯誤。

這個機制也體現了 Swift 型別安全的核心思想。如果我們覺得每個列舉項都要明確的指定行為比較麻煩,我們還可以使用 default 分支來對於其餘的列舉項定義行為:

switch weekday {

case .Saturday:
    println(":)")
case .Sunday:
    println(":)")
default:
    println(":(")

}

總之,無論用 default 也好,還是明確對每一個列舉項指定行為也好,在 Swift 中,我們都必須對列舉型別下的每個值,指定確定的行為。不能漏掉其中任何一個可能性。

關聯值(Associated Values)

在 Swift 中,我們還可以定義這樣的列舉型別,它的每一個列舉項都有一個附加資訊,來擴充這個列舉項的資訊表示,這又叫做關聯值。加入我們有一個列舉型別Shape 來表示形狀。
這個形狀可以是矩形,也可以是圓形,等等。而每種具體的形狀又對應了不同的屬性,比如矩形有長,寬,圓形有,圓心,半徑,等等。那麼列舉的關聯值就可以幫我們解決這個問題:

enum Shape {

    case Rectangle(CGRect)
    case Circle(CGPoint,Int)

}

我們看到,每個列舉項的後面,都包含了一對括號,這裡面定義了這個列舉項的關聯值的型別。對於 Rectangle 我們使用一個 CGRect 來表示他的原點和長寬屬性。
而對於 Circle,我們使用一個包含了 CGPointInt 型別的元組(Tuple) 來表示這個圓的圓心和半徑。

這樣我們在初始化列舉型別的時候,我們就可以根據每個列舉項的關聯值型別,為它指定附加資訊了:

var rect = Shape.Rectangle(CGRectMake(0, 0, 200, 200))
var circle = Shape.Circle(CGPointMake(25, 25), 20)

這樣的列舉用法,是不是覺得非常方便呢, 有木有腦洞小開的感覺呢,嘿嘿~

我們再看一下,帶有關聯值的列舉項在 switch 語句中的用法:

switch(rect) {

case .Rectangle(let rect):
    println("this is a rectangle at \\\\(rect)")
case let .Circle(center, radius):
    println("this is a circle at \\\\(center) with radius \\\\(radius)")

}

我們在 case 後面用一對括號來輸出列舉項的關聯值,可以用 let 或者 var 關鍵字,分別作為常量和變數進行輸出。我們這裡這樣來使用case .Rectangle(let rect)。對於關聯值是包含多個值的元組型別的,我們可以將 let 關鍵字放置在列舉項型別的前面,這樣就可以不用對每個關聯值都宣告let 關鍵字了,let .Circle(center, radius)。

原始值(Raw Values)

我們剛剛瞭解了關聯值型別的列舉的使用,Swift 的列舉型別還提供了另外一個叫做原始值(Raw Values)的實現。和關聯值不同,它為列舉項提供一個預設值,這個預設值是在編譯的時候就確定的。而不像關聯值那樣,要再實力化列舉值的時候才能確定。

這也就是說,原始值對於同一個列舉項都是一樣的。而關聯值對於同一個列舉項只是值的型別相同,但具體的取值也是不同的。

下面我們來看一下定義列舉原始值 (Raw Values) 的方法:

enum WeekDayWithRaw : String {

    case Monday = "1. Monday"
    case Tuesday = "2. Tuesday"
    case Wednesday = "3. Wednesday"
    case Thursday = "4. Thursday"
    case Friday = "5. Friday"
    case Saturday = "6. Saturday"
    case Sunday = "7. Sunday"

}

還是表示星期的列舉型別,我們對每個列舉項都定義了一個預設的原始值,注意一下我們定義列舉的第一行程式碼,enum WeekDayWithRaw : String 我們在列舉定義的最後,多加了一個String
關鍵字,這就表示這個列舉的原始值(Raw Values) 是 String 型別的。

在我們下面的定義中,也體現了這一點。對於所有的列舉項,我們賦給的原始值都是 String 型別的。

定義好了原始值後,我們就可以用列舉項的 rawValue 屬性來輸出它:

println(WeekDayWithRaw.Saturday.rawValue)  //6. Saturday

我們還可以通過原始值(Raw Values) 來初始化列舉型別:

let day = WeekDayWithRaw(rawValue: "3. Wednesday")

這個初始化方法的返回值是一個 Optionals。所以我們可以用 Optionals 的組合鏈來使用它的返回值:

if let day = WeekDayWithRaw(rawValue: "3. Wednesday") {
    println(day)
}else{
    println("init fail")
}

返回值為 Optionals 的型別,代表這個方法可以返回一個具體的值,也可以返回 nil, 因為我們傳入初始化方法的原始值,可能會不等於我們預設的那幾個值,比如我們這樣初始化一個列舉:

let day = WeekDayWithRaw(rawValue: "No Exist Value")

如上面所示,"No Exist Value" 這個值和我們定義個原始值列表中任何一項都不對應,所以這個初始化是會失敗的,在這種情況下初始化方法會返回 nil,來表示初始化失敗。

所以基於這種情況,我們需要對返回值進行判斷,這也就是我們上面的 if 判斷的用處所在:

if let day = WeekDayWithRaw(rawValue: "3. Wednesday") {
    println(day)
}else{
    println("init fail")
}