這裏爲啥要叫枚舉類而不是枚舉類型呢?因爲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
用來給每一個枚舉成員再定義一個補充值。下面是官方的例子。
我們知道商品的條形碼和二維碼。條形碼是由一串數字組成的,這個數字分爲了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
}
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"