您的位置:首页 > 移动开发 > Swift

Swift学习笔记8——枚举类(Enumerations)

2015-10-03 11:43 399 查看
这里为啥要叫枚举类而不是枚举类型呢?因为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"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: