SwiftNote-增强的枚举 enum

344 阅读3分钟

枚举语法

用 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 枚举来存储任意给定类型的关联值,如果需要的话不同枚举成员关联值的类型可以不同。

比如一个库存系统的标签有两种:条形码 和 二维码

  • 条形码由四部分数字组成
  • 二维码其实代表的是一个字符串

code

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