枚举语法
用 enum 关键字来定义一个枚举,然后将其多定义的内容放在一个大括号里面,多个成员值可以出现在同一行,用逗号隔开。
enum CompassPoint {
case north
case south
case east
case west
}
使用 switch 语句来匹配枚举
func enumMatch(direction: CompassPoint) {
switch direction {
case .south:
print("向南出发")
case .north:
print("向北出发")
case .east:
print("向东出发")
case .west:
print("向西出发")
}
}
let direction = CompassPoint.south
enumMatch(direction: direction) // 向南出发
遍历枚举的 case
对于一个遵循了 CaseIterable 协议的枚举,swift 会提供一个包含所有枚举类型的集合,集合名为 allCases。
enum CompassPoint: CaseIterable {
case north
case south
case east
case west
}
let numberOfDirections = CompassPoint.allCases.count
print("\(numberOfDirections) directions")
// 4 directions
for direction in CompassPoint.allCases {
print(direction)
}
// north
// south
// east
// west
关联值
可以定义 swift 枚举来存储任意给定类型的关联值,如果需要的话不同枚举成员关联值的类型可以不同。
比如一个库存系统的标签有两种:条形码 和 二维码
- 条形码由四部分数字组成
- 二维码其实代表的是一个字符串
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 42312, 3)
print(productBarcode)
// upc(8, 85909, 42312, 3)
productBarcode = .qrCode("ABCDEFGH")
print(productBarcode)
// qrCode("ABCDEFGH")
// 使用值绑定可以得到每个关联值
switch productBarcode {
case .upc(let numberSystem, let manufactirer, let product, let check):
print("UPC: \(numberSystem), \(manufactirer), \(product), \(check)")
case .qrCode(let code):
print("QRCode: \(code)")
}
// QRCode: ABCDEFGH
预设初始值
当你在操作存储整数或字符串原始值枚举的时候,你不必显式地给没一个成员变量都分配值。当你没有分配时,swift 会自动为你赋值。
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, nepture
}
enum Direction: String {
case north, south, east, west
}
如果你用原始值类型定义了一个枚举,那么枚举就会自动收到一个可以接受原始值类型的值的初始化器(叫做 rawValue 的形式参数),然后返回一个枚举值或者 nil。可以使用这个初始化器来创建一个枚举的新实例。
let possiablePlanet = Planet(rawValue: 7)
print(possiablePlanet)
// 返回了一个 Planet 的枚举实例
// Optional(MTSwift.Planet.uranus)
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) {
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("there is not a planet at position: \(positionToFind)")
}
// Planet(rawValue: positionToFind) 返回的是一个 nil,因为我们的 Planet 枚举关联值 1~8,并不包含 11
// there is not a planet at position: 11
递归枚举
递归枚举是拥有另一个枚举作为枚举成员关联值的枚举。当编译器操作递归枚举时必须插入间接寻址层。你可以在声明枚举成员之前使用 indirect 关键字来明确它是递归的。
比如说表达式 (5+4)*2 在乘法右侧有一个数但有其他表达式在乘法的左侧。
// 定义递归枚举
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
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)
}
}
let four = ArithmeticExpression.number(4)
let five = ArithmeticExpression.number(5)
let sum = ArithmeticExpression.addition(four, five)
let result = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
print(evaluate(result)) // 18