序言
枚举类型在swift中运用亦相当广泛,也很重要。枚举为一组相关值定义了一个共同类型,并且使你能够用一种类型安全的方式在代码中处理那些值。在swift中枚举更加灵活,不必要为枚举的每一个case提供一个值。如果每一个枚举case提供一个值(比如“raw”), 那个这个值可以是字符串, 字符, 任意的整型值或浮点类型。
本章目录
- 枚举语法
- 枚举值和Switch语句搭配
- 关联值
- Raw Values(原始值)
- 原始值的隐式赋值
- 从原始值初始化
- 递归枚举
枚举语法
和以前定义的枚举类似,swift中的枚举也很简单,例如:
// 定义枚举
enum MyEnumeration {
case age
case height
case weight
case lungVolume
}
// 打印枚举成员值
print(MyEnumeration.age)
print(MyEnumeration.height)
print(MyEnumeration.weight)
print(MyEnumeration.lungVolume)
// 打印结果
age
height
weight
lungVolume
需要注意的是, 和C、OC中不一样,如果不指定枚举类型,则swift中的枚举在被创建后不会分配一个默认的整型值。
如果没有指定枚举类型, 则不能给枚举成员赋值,下面的方式错误:
enum YourEnumeration {
case handsNumber = 2 ------------报错
case feetNumber = 2 ------------报错
}
如果指定了枚举类型, 就可以直接给枚举成员赋值! 并且如果不赋值,对于Int来说,枚举成员就会被默认为 0, 1, 2……. 还有就是如果给枚举指定了类型, 则枚举成员就存在rawValue值!
e.g:
enum MyEnumeration: Int {
case age
case weight
case height
case lungVolume
}
print(MyEnumeration.age.rawValue)
print(MyEnumeration.weight.rawValue)
print(MyEnumeration.height.rawValue)
print(MyEnumeration.lungVolume.rawValue)
//prints output
0
1
2
3
枚举成员也可以写在同一行:
enum SimpleEnumeration {
case age, height, weight
}
Swift中,枚举类型名要首字母大写(尽管小写的时候编译器也不会报错),而且类型名最好是单数, 不要起复数名字, 这样读起来清晰明白。
有时, 如果我们明确了枚举成员变量, 则可以使用点语法来改变它的成员:
var myDescription = MyEnumeration.age
myDescription = .weight
myDescription = .height
枚举值和Switch语句搭配
有时候我们需要判断枚举成员值是否属于某一个值, 这时我们就可以使用Switch语句来判断:
myDescription = .weight
switch myDescription {
case .age:
print("年龄")
case .height:
print("身高")
case .weight:
print("体重").............结果打印这里,因为匹配到了
}
上面这个Switch例子没有default:语句,是因为case当中已经列举了枚举中所有会出现的可能!
关联值
有时对于能够存储在case值的其他类型的关联值来说是很有用的。这是你能够存储额外和case值相关的自定义信息, 并且每当你在代码中使用那个case的时候允许这些信息变化。
简单举个例来说, 就是我们常见的条形码和二维码, 条形码一般是由一连串数字组成,二维码一般是由字符串组成,这是我们就可以用关联值来处理它们。
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
// 使用switch语句匹配关联值
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
// 打印结果
QR code: ABCDEFGHIJKLMNOPQRSTUVWXYZ
// 如果某个case个关联值都是常量或者变量, 可以只用一个 let 或 var 写在case名前, 这样更简洁
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
Raw Values(原始值)
枚举成员可以预填充默认值(raw values), 但是默认值必须是同一类型。
enum SomeString: String {
case xiaoming = "lll"
case zhangsan = "kkk"
case likeqiang = "ppp"
}
枚举SomeString的raw values值定义成 String类型, 每一个原始值(raw value)在枚举声明中必须唯一。
注意: 原始值和关联值不一样, 原始值是当你在代码中开始定义枚举的时候所设值的预填充值, 就如上面的 “lll”、“kkk”、“ppp”, 类型是String. 对于特定枚举成员来说, 原始值始终一样! 关联值是当你创建基于枚举成员的新的常量或变量才设置的值, 并且每次你创建的可以不同, i.e, 关联值可以改变。
原始值的隐式赋值
当你处理储存Int原始值或者String原始值的枚举时,你就没必要给每个case成员显式赋一个原始值, 因为就算你不指定成员的初始值, swift也会自动为你赋值。
enum RawValueEnumeration: Int {
case value1 = 1, value2, value3, value4
}
如上面的枚举, 枚举成员value1有一个明确的初始值1, value2的为2, value3的rawValue为3……
当你使用字符串作为原始值时, 每个case成员的隐式赋值就是它本身。
enum ImplicitEnumeration: String {
case chenlong
case langke
}
上面的例子中, ImplicitEnumeration.chenlong的隐式原始值就是chenlong……
// 我们可以通过rawValue属性来获取枚举成员的原始值
let myRawValue = ImlicitEnumeration.chenlong.rawValue
// 打印结果:chenlong
print(myRawValue)
从原始值初始化
如果你定义了一个raw value类型的枚举, 那么这个枚举就会自动接收一个带原始值类型的值的初始化器,并且要么返回枚举成员,要么返回nil。你能够使用这个初始化器来创建一个新的枚举实例!
enum Barcode: Int {
case langke0
case langke1
case langke2
case langke3
case langke4
}
let langke00 = Barcode(rawValue: 0)
// 打印结果:Barcode.langke0, 并且是Barcode?
print(langke00)
let langke00 = Barcode(rawValue: 5)
// 打印结果:nil, 因为原始值为5的成员没有, 原始值默认是:0...4
print(langke00)
从上面的例子可以看出,并非所有的可能Int值都会找到匹配的Barcode, 正因为如此, 所以raw value初始化器总是返回一个可选的枚举成员!
另外值得注意的是: 原始值初始化器是一个可失败初始化器, 因为并非每个原始值都会返回一个枚举成员。
let caseValue = 5
if let langke5 = Barcode(rawValue: caseValue ) {
switch langke5 {
case .langke0, .langke1, .langke2, .langke3:
print("要么是langke0, 或langke1, 或langke2, 或langke3")
default:
print("只剩下一个langke4")
}
} else {
print("绝没有langke5这个成员!")
}
// 结果:绝没有langke5这个成员!
递归枚举
何为递归枚举?
递归枚举就是一个让另一个枚举实例作为当前枚举一个或多个枚举成员的关联值的枚举。简单解释一下就是, 当前枚举的枚举成员的关联值含有另外的枚举实例, 有可能只有一个枚举成员含有另一个枚举实例, 也可能有多个枚举成员有另一个枚举实例!!!
通过在枚举成员前面写 indirect ,你可以表明一个枚举成员就是递归的!
下面来看一个官方例子:
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
PS: 我们也可以在枚举开始前写 indirect 来使所有需要它的枚举成员递归
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
我们接着来计算一个例子: (5 + 6)* 2 , 结果应该等于 22
分析一下:
乘号左边是一个加法表达式,右边是一个数字, 因为数据嵌套了, 所以存储这个数据的枚举也需要支持嵌套—这意味着枚举需要递归。下面看一个具体的例子
let five = ArithmeticExpression.number(5)
let six = ArithmeticExpression.number(6)
let sum = ArithmeticExpression.addition(five, six)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
// 打印结果:22
print(evaluate(product))
上面这个例子就很好地突出递归枚举的作用, case后面跟了可选绑定let关键字和关联值, 以此来确定要返回的值通过evaluate函数返回计算的值。
枚举的使用时很灵活的, 我们可以用在工程函数中, 也可以用在一般的条件语句中, 也可以简单地和Switch等语句搭配来匹配相应的值。有时使用枚举可以让代码更加简洁明了, 增强代码的迭代性。
本文来自Swift3.0.1官方英文版, 作者自译, 欢迎学习, 禁止用于商业用途, 侵权必究! 由于个人能力有限, 欢迎指出其中不足之处!