Swift學習筆記8——枚舉類(Enumerations)

這裏爲啥要叫枚舉類而不是枚舉類型呢?因爲Swift中的枚舉和C中的枚舉很不一樣。它已經可以看成一個類,可以看成一個類,可以看成一個類。重要的事情說三遍。此外,它是值傳遞!

在C中,枚舉類型中的每一項都整形,然而在Swift中,你不必爲每一項賦值。定義的時候所用的名字就是用來枚舉的。當然你也可以爲枚舉成員賦值,這個賦值不單單是整形,可以是Charater,String,浮點數。

下面定義一個枚舉類型。

enum NameSet {  //注意首字母已經大寫
    case Lucy
    case Tom
    case Kate
    case Aaron
}

enum NameSet2{   //可以將枚舉成員都寫在一行,用逗號分隔
    case Lucy, Tom, Kate, Aaron
}


定義一個枚舉變量

var myName = NameSet.Aaron
myName = .Kate  //因爲已經聲明瞭myName是NameSet類型,所以改變值的時候可以直接用 .Kate


Associated Value
用來給每一個枚舉成員再定義一個補充值。下面是官方的例子。

我們知道商品的條形碼和二維碼。條形碼是由一串數字組成的,這個數字分爲了4個部分。而二維碼其實是用一串很長的字符來編碼的。如果要把二位碼和條形碼封裝成爲一個枚舉類型,爲了更好地區別二者,我們可以加上associated value,定義如下

enum Barcode {
    case UPCA(Int, Int, Int, Int) //條形碼
    case QRCode(String)           //二維碼
}

定義Barcode變量,同是添加上associated value

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
這裏要注意的一點是,如果你定義了associated value,那麼在定義變量的時候就和前面的NameSet不太一樣了。看下面的兩句代碼

var b1 = Barcode.UPCA(8, 85909, 51226, 3)
var b2 = Barcode.QRCode
b1和b2究竟是什麼類型呢?

答案是b1是Barcode類型,b2是(String) -> Barcode類型,一個函數類型。

所以當你想用 

b2 = Barcode.QRCode("fef")  //error
報錯 不能將 Barcode類型是值賦給 (String)->Barcode.

這裏就可以看出了,其實Barcode.QRCode(String:)是一個構造函數,這裏再次驗證了swift中的枚舉是一個類。


那爲啥NameSet裏面可以直接用.Tom之類來賦值呢?我的猜測是當你定義了associated value的時候,相當於把該枚舉成員從一個值變爲了構造方法。


switch語句來處理枚舉類

接下來看看使用swift強大的switch語句來處理枚舉類,除了一般的枚舉成員之外,對於帶associated value 的成員,我們還可以得到associated value。

enum NameSet {  //重新定義一個簡單的枚舉類
    case Lucy
    case otherName(String)
}

var myName = NameSet.Lucy
myName = .otherName("Alexs")

switch myName {
case .Lucy:
    print(myName)
case .otherName(var inputName):  //使用括號解包出associated value
    print(inputName)     //只有這句會打印出  Alexs
}

我們修改一下上面的switch如下,你覺得那句會打印呢?

switch myName {
case .Lucy:
    print(myName)
case .otherName:
    print("otherName")
case .otherName(var inputName):
    print(inputName)
}
這裏打印的是otherName,這裏可以看出,switch裏面的.otherName和聲明枚舉變量時候的不同,這裏已經是值NameSet的值了。而且上面的Switch也會有警告說最後一個case永遠不能執行。括號只是用來解包出associated value,而不是構造方法。爲了驗證這一點,再改改上面代碼

var myName = NameSet.Lucy

switch myName {
case .Lucy(let name):
    print(name)
case .otherName:
    print("otherName")
case .otherName(var inputName):
    print(inputName)
}
你會發現這裏打印了 (),因爲解包Lucy沒有得到值。

這裏再回顧一下switch語句,之前說過只有窮盡枚舉的時候纔不需要default選項。上面的例子中因爲把NameSet裏面所有可能都枚舉了,所以不需要default選項。


Raw Value

這個就是對每一項枚舉成員綁定一個值,好比是C裏面的枚舉成員都是一個整形。

如果需要Raw Value,必須在聲明枚舉類的時候加上raw value 的類型。

比如官網例子

enum ASCIIControlCharacter: Character {
    case Tab = "\t"
    case LineFeed = "\n"
    case CarriageReturn = "\r"
}

和C有默認的raw value一樣,swift的枚舉類也有默認的raw value。但是不是任何類型的raw value 都有默認值。假如你raw value的類型是Character,那麼就不存在默認raw value,每個枚舉成員的默認值都必須由你自己定義。

如果類型是Int,那麼默認值第一個是0,後面的一項都前一項加1.看下面例子就明白了

enum NameSet: Int{
    case Lucy      //0
    case Tom = 3   //3
    case Kate      //4
    case Angle = 66  //66
    case Alex      //67
}


如果類型是String,那麼默認值就是你的枚舉成員的名字。

enum NameSet: String{
    case Lucy       //Lucy
    case Tom = "T"  //T
    case Kate       //Kate
}

如果有raw value,就可以用raw value來定義枚舉變量

var myName = NameSet(rawValue: "Lucy")   //注意這裏返回的是一個可選類型,因爲這個構造方法是一個可失敗的構造方法。具體看後面的類構造的文章。
print(myName!.rawValue)      //這裏我就沒用if做判斷了,直接強制解包

遞歸enum

就是在enum的枚舉成員的associated value聲明爲本枚舉類。然後使用遞歸函數。這裏附上官方例子。實際的應用有待研究。

在聲明associated value爲自己枚舉類的時候,需要加上indirect關鍵字。這個關鍵字可以加在每個case的前面,也可以加在enum的前面。後一種方法對裏面所有的case都起效。但是並不要求所有case都有本枚舉類作爲associated value。

indirect enum ArithmeticExpression {  //使用第二種indirect。定義了一個數學表達式。
    case Number(Int)
    case Addition(ArithmeticExpression, ArithmeticExpression)
    case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
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)
    }
}
 
// evaluate (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))
// prints "18"

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章