枚举类型定义了一组相关值的共同类型,比如东、西、南和北具有的共同类型就是方向,可以定义一个方向的枚举类型,包含它们。枚举类型能够让你在代码中使用类型安全的的值。C语言中的枚举类型是提供了一组整数值和枚举值相对应,但是Swift中的枚举更加灵活,并没有使用响应的整数值。枚举类型中的值称之为原生值(raw value),可以是字符串、字符或者整型和浮点型。
Swift中的枚举类型是一等类型(first-class type),采取了只有类才支持的许多特性,比如计算属性,实例方法等。下面来看看枚举的具体知识点。
Swift的枚举类型比C语言的功能更加强大,在Swift中枚举是一等类型,可以支撑属性和方法。采用enum关键字,定义的主体放在花括号中。
定义语法示例:
enum enum_name {
case value1, value2, ...
}
或者是:
enum enum_name{
case value1
case value2
...
}
如果将所有的case都写在一行的话,就只需要一个case;如果写作多行的话,就需要多个case关键字。如:
enum Method{
case Add, Sub, Mul, Div
}
enum Method {
case Add
case Sub
case Mul
case Div
}
声明枚举变量:
var m0: Method = .Add (指定了类型)
var m1 = Method.Add (没有指定类型时)
由于Swift的类型推断非常强大,它能推断出m0属于Method这个枚举类型的,所以采用“.”运算符的时候可以不写枚举的类型。和C语言不一样的是,当创建枚举类型的时候,Swift并没有提供默认的相应的整数值。比如Add、Sub、Mul和Div不会隐性地被赋值为0,1,2,3。
先来看一个实例:
func chooseMethod(op: Method) ->(Double, Double) -> Double{
switch op {
case .Add:
// 函数
func add(a: Double, b: Double) -> Double{
return a + b
}
return add
case .Sub:
// 闭包
return{
(a: Double, b: Double) -> Double in
return a - b
}
case .Mul:
// 简写闭包
return {
return $0 * $1
}
case .Div:
// 简写闭包
return {$0 / $1}
}
}
}
let val = chooseMethod(.Add)(20,30)
print(val)
在switch case语句中必须匹配完枚举类型中的所有值,如果没有匹配完,则需要加default 语句。这个实例比较好地阐释了枚举类型和switch-case语句配合使用的具体实现。
为了兼容C语言,可以将上面的Method定义为:
enum Method: Int{
case Add
case Sub
case Mul
case Div
}
此时,Add,Sub,Mul和Div默认对应的原始值为0,1,2,3。可以改变某一个枚举值对应的原始值,那么改变的枚举值的后面的枚举值对应的原始值都会改变。如
enum Method: Int{
case Add
case Sub = 3
case Mul
case Div
}
则此时,Add,Sub,Mul和Div默认对应的原始值为0,3,4,5。可以打印出原始值:
print(Method.Add.toRaw())
如果原始值的类型不是Int,则应该给每个枚举值都指定对应原始值。
原始值和枚举值的相互转换:
枚举值转化为原始值:toRaw()
原始值转化为枚举值:Method.fromRaw() [该方法返回一个可选值]
枚举的原始值用的场合并不多,仅当了解。
有时候其他类型的值伴随着这些case值一起存储的话会非常有用,你可以定义枚举类型存储任何类型的关联值,如果需要的话,也可以为每个case的值分配不同类型的关联值。比如商品的条形码有一维码和二维码之分,一维码采用UPC格式,由四组数字组成,第一组是0-9,只有一个数,表示数字系统,第二组是由五位数组成,表示生产代码,第三组也是五位数字,产品代码,最后一组由一位数字组成,表示校验码。其他有些产品的条形码采用二维码的形式,它可以编码为字符串。
我们可以定义这样的枚举类型:
enum Barcode{
case upc(Int, Int, Int, Int)
case qr(String)
}
我们可以这样理解这个枚举类型:定义了一个名称为Barcode的枚举类型,这个枚举既有一个和(Int, Int, Int, Int)
关联值类型关联的值,又有一个和String
关联值类型关联的值。就是说它有两个值,一个值和元组类型的值相关联,另一个和String类型的值相关联。这仅仅是定义了这个枚举类型,并没有给它提供任何的实际的值。我们可以这样使用它:
//定义了一个Barcode枚举类型的变量,而这个变量的值是upc,它和
//元组(8, 85909, 51226,3)这个值相关联。
var productCode = Barcode.upc(8, 85909, 51226, 3)
//相同的产品也可以用二维码表示
productCode = .qr("ABCDEFGHIJKLMN")
//这样原来的upc的值以及的它的关联值就被替换为qr和它的关联值了。
枚举类型也是一种数据类型,所以变量或者常量的值只能取这个枚举类型的一个值,如productCode
只能是upc
或者是qr
。
那么这个关联值有什么用呢?关联的值只是为了存储额外的信息,所以还是要访问这些额外信息的。如下面具有关联值的枚举类型与switch语句相结合。
switch productCode{
case .upc(let numberSystem, let manufacturer, let productCode, let check):
print("UPC: \(numberSystem), \(manufacturer), \(productCode), \(check)")
case .qr(let productCode):
print("QR code: \(productCode)")
}
枚举值和一个确定的值对应,则是原始值,如果枚举值和多个值对应,则一般称这多个值为关联值,一般用元组表示。再比如在x轴上的一条线段,它有两种表示方法,一种是给定起点和终点,一种是给定起点和长度(给定终点和长度与此表示方法一致),用枚举表示为:
enum LineSegment{
case StartAndEnd(start: Double, end: Double) //后面跟一个元组,下同
case StartAndLength(start: Double, length: Double)
}
使用:
let line: LineSegment = .StartAndEnd(start: 10, end: 20)
let line1 = LineSegment.StartAndLength(start: 10, length: 10)
递归枚举是一种将其他枚举实例作为关联值的枚举类型。用关键字indirect
表明这个case
值是递归的,它告诉编译器来插入所需的间接层。
比如以下的枚举类型:
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
也可以将indirect提到enum的前面:
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
这个枚举类型存储着三种数学表达式:纯数字、加法表达式和乘法表达式。而加法表达式和乘法表达式又和 ArithmeticExpression类型的值相关联。如下面的使用:
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, .number(2)) // 2 * (4 + 5)
我们可以定义一个函数来计算这个表达式的值:
func calculate(expression: ArithmeticExpression) -> Int{
switch expression {
case .number(let value):
return value
case .addition(let add1, let add2):
return calculate(add1) + calculate(add2)
case .multiplication(let mul1 , let mul2 ):
return calculate(mul1) * calculate(mul2)
}
}
print("the result is : \(calculate(product))")
结果为:
the result is : 18
Program ended with exit code: 0