Swift文档Chapter 8 枚举


枚举为一组相关值定义了一个共同的类型,在代码中可以以类型安全的方式访问这些值。

枚举语法

enum enumType{
    case value1
    case value2
    case value3
}

使用case可以定义一个新的枚举值。同时,枚举值是完备的,不会像C语言一样分配一个默认的整形值。
可以使用逗号分隔在同一行定义多个枚举值。枚举的名字使用大写字母开头,并且使用单数。一旦某一个变量被声明为枚举类型,那么可以直接使用.访问成员。如果变量的枚举类型已知,可以在赋值时省略枚举类型,直接用.访问成员。

使用Switch语句匹配枚举值

Switch语句匹配枚举值时会强制枚举,如果某些值没有考虑时,编译就会报错。不需要匹配的值可以使用default进行匹配。

枚举值的遍历

令枚举遵循CaseIterable协议,那么Swift会为枚举加入allCases属性。这个属性可以使用for-in遍历,同时也可以调用allCases属性的count属性获得枚举值个数。遵循协议需要在枚举名后面加上冒号后去使用这个协议。

关联值

我们可以给我们的枚举值关联一个值,类似于为枚举值赋值。关联值的定义如下:

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

关联值只定义类型,当把枚举值赋值的时候,可以在后面加上括号并赋一个关联值。

var productBarcode = Barcode.upc(8, 85909, 51226, 3)

这个时候我们在使用switch语句匹配的时候,可以同时获得关联值的量:

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).")
}

当所有的关联值都需要都被提取为变量或者常量,那么可以在成员名称前标注一个let或者var

switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
    print("QR code: \(productCode).")
}

原始值

枚举成员可以被原始值预填充,这些值必须类型一致。这种方法更贴近于C语言中的枚举。
以ASCII码枚举为例:

enum ASCIIControlCharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}

我们定义这个枚举为Character类型的枚举并赋对应值。原始值的类型可以为字符串,字符,任意整型和浮点型。

原始值和关联值是不同的。原始值是在定义枚举时被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终不变。关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化。

原始值的隐式赋值

  • 整型:每一个枚举值依次加1,如果第一个枚举值不赋初值,枚举值默认为0;
  • 字符串:默认赋值和枚举成员的枚举名一致。

使用原始值初始化枚举实例

我们使用enumType(rawValue:)的方式初始化一个枚举值,返回值是一个可选类型,不一定每一个原始值都可以得到对应的枚举。

递归枚举

case前加上indirect表明这个成员是可以递归的。在enum前加上indirect表明所有的成员都是可以递归的。

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)
    }
}