首页 > 代码库 > Swift 学习- 09 -- 枚举

Swift 学习- 09 -- 枚举

// 递归枚举

// 美家居为一组相关的值定义了一个共同的类型, 使你可以在代码中以类型安全的的方式使用这些值.

 

// 如果你熟悉C语言, 你会知道在C语言中, 枚举会为一组整型值分配相关联的名称, swift 中的枚举更加的灵活, 不必给每一个枚举成员提供一个值,如果给枚举成员提供一个值 (称为原始值), 则该值的类型可以是字符串,字符, 或者是一个整型值或浮点数,

 

// 此外, 枚举成员可以指定任意类型的关联值存储到枚举成员中, 你可以在一个枚举中定义一组相关的枚举成员, 每一个枚举成员都可以有适当类型的关联值,

 

 

// 枚举语法

// 使用enum 关键字来创建枚举并且把它们的真个定义放在一堆大括号内

 

enum SomeEnumeration{

    // 枚举定义放在这里

}

 

// 下面用枚举表示指南针四个方向的例子

 

enum CompassPoint {

    case north

    case south

    case east

    case west

}

 

// 枚举中定义的值 (如 north, south, east ,west) 是这个枚举的成员值(或成员), 你可以使用 case 关键字来定义一个新的枚举成员值

 

// 注意 : 与 C语言和 OC 不同, swift 的枚举成员在被创建时不会被赋予一个默认的整型值,在上面的 CompassPoint 例子中, north, south ,east 和 west 不会被隐式地赋值为0,1,2,3 ,相反,这些枚举成员本身就是完备的值,这些值的类型是已经是明确定义好的 CompassPoint 类型

 

// 多个成员可以出现在同一行上, 用逗号隔开

 

enum Planet {

    case mercuty, venus,earth, jupiter, saturn, uranus, neptune

}

 

// 每个枚举定义了一个全新的类型, 像 Swift 中其他类型一样, 他们的名字,应该以一个大字母开头, 给枚举类型起一个单数名字而不是复数名字, 以便于读起来更加容易理解

var directionToHead = CompassPoint.west

 

// directionToHead 的类型可以在它被 CompassPoint 的某个值初始化时推断出来, 一旦 directionToHead 被声明为 CompassPoint 类型, 你可以使用更简短的点语法将其设置为另一个 CompassPoint 的值,

directionToHead = .east

 

// 当 directionToHead 的类型已知时, 再次为其赋值可以省略枚举类型名, 在使用具有显式类型的枚举值时, 这种写法让代码有更好的可读性

 

 

 

// 使用 Swift 语句匹配枚举值

// 你可以使用 Swift 语句匹配单个值:

directionToHead = .south

switch directionToHead {

case .north:

    print("Lots of planets have a north")

case .south:

    print("Watch out for penguins")

case .east:

    print("Where the sun rises")

case .west:

    print("Where the skies are blue")

default:

    print("none")

}

 

// 在判断一个枚举类型的值时 ,Swift 语句必须穷举素有的情况, 当不需要匹配每个枚举成员的时候, 你可以提供一个 default 分支来涵盖所有未明确处理的枚举成员

 

let somePlanet = Planet.earth

switch somePlanet {

case .earth:

    print("Mostly harmless")

default:

    print("Not a safe place for humans")

}

 

 

 

// 关联值

// 有时候能够把其他类型的关联值和成员值一起存储起来会更有用, 这能让你连同成员值一起存储额外的自定义信息,并且你每次在代码中使用该枚举成员时, 还可以修改这个关联值

 

// 你可以定义 Swift 枚举来存储任意类型的关联值, 如果需要的话, 每个枚举成员的关联值类型可以各部相同, 枚举的这个特性跟其他语言中的可识别联合, 标签联合, 或者变体相似

 

// 例如: 假设一个库存跟踪系统需要利用不同类型的条形码来跟踪商品,有四个数字,其他商品上标有 QR 码格式的二维码, 它是可以使用任何字符的字符串

 

// 在 Swift 中, 使用如下方式定义表示两种商品条形码的枚举

 

enum Barcode{

    case upc(Int,Int,Int,Int)

    case qrCode(String)

}

 

// 以上可以这么理解 : "定义一个名为 BarCode 的枚举类型, 它的一个成员是具有 (Int, Int, Int, Int) 类型关联值的upc, 另一个成员是具有 String 类型关联值的 qrCode"

 

// 这个定义不提供任何 Int 或者 String 类型的关联值, 它只是定义了, 当 BarCode 常量和变量等于 Barcode.upc 或者 Barcode.qrcode 时, 可以存储的关联值的类型

 

// 然后可以使用任意一种条形码类型创建新的条形码, 例如: 

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

 

// 上面的例子创建了一个名为 productBarcode 的变量, 并将 Barcode.upc 赋值给它,

 

// 同一个商品可以被分配一个不同类型的条形码, 例如:

productBarcode = .qrCode("BJUIBHYUGVUTYFVFY")

 

// 这时,原始的 Barcode.upc 和其整数关联值被新的 Barcode.qrCode 和其字符串关联值所替代, Barcode 类型的常量和变量可以存储一个 .upc 或者一个 .qrCode,(连同他们的关联值), 但是在同一时间只能存储两个值中的一个

 

 

// 像先前那样,可以使用一个 switch 语句来检查不同的条形码类型。然而,这一次,关联值可以被提取出来作为 switch 语句的一部分。你可以在switch的 case 分支代码中提取每个关联值作为一个常量(用let前缀)或者作为一个变量(用var前缀)来使用:

 

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: ABCDEFGHIJKLMNOP."

// 如果一个枚举成员的所有关联值都被提取为常量,或者都被提取为变量,为了简洁,你可以只在成员名称前标注一个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).")

}

// 输出 "QR code: ABCDEFGHIJKLMNOP."

 

 

 

// 原始值

// 在上个例子中, 演示了如何声明存储不同类型关联值的枚举成员, 作为关联值的替代选择, 枚举成员可以被默认值 (称为原始值) 预填充, 这些原始值的类型必须相同

 

// 原始值 可以是字符串, 字符,或者任意整型或是浮点型, 每个原始值在枚举声明中必须唯一的.

 

// 注意 : 原始值和关联值是不同的,原始值是在定义枚举是被预先填充的值, 对于一个特定的枚举成员,它的原始值始终不变, 关联值是创建一个基于枚举成员的变量或是常量是才设置的值, 枚举成员的关联值可以变化

 

 

 

 

// 原始值的隐式赋值

// 在使用原始值为整数或者字符串类型的枚举时, 不需要显式地为每一个枚举成员设置原始值, Swift 将会自动为你赋值

// 例如,当使用整数作为原始值时,隐式赋值的值依次递增 1, 如果第一个枚举成员没有设置原始值, 其原始值将为0 

 

enum Planet2: Int {

    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune

}

// 在上面的例子中,Plant.mercury的显式原始值为1,Planet.venus的隐式原始值为2,依次类推。

 

// 当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。

 

// 下面的例子是CompassPoint枚举的细化,使用字符串类型的原始值来表示各个方向的名称:

 

enum CompassPoint2: String {

    case north, south, east, west

}

 

// 上面的例子中, CompassPoint2.south 拥有隐式原始值 south ,依次类推

// 使用枚举成员的 rawValue 属性可以访问该枚举成员的原始值

 

let earthsOrder = Planet2.earth.rawValue

 

let sunsetDirection = CompassPoint2.west.rawValue

 

 

 

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

// 如果在定义枚举类型的时候使用了原始值, 那么将会自动获得一个初始化方法, 这个方法接收一个叫做 rawValue 的参数,参数类型即为原始值类型, 参数类型即为原始值的类型, 返回值则是枚举成员或是 nil, 你可以使用这个初始化方法来创建一个新的枚举实例

 

// 这个例子利用原始值 7 创建了新的枚举成员 uranus:

 

let possiblePlanet = Planet2(rawValue: 7)

 

// 然而, 并非所有 Int 值都可以找到一个匹配的枚举成员, 因此, 原始值构造器总是返回一个可选的枚举成员, 在上面的例子中, possiblePlanet 是 Planet2? 类型, 或者说是 ‘可选的 Planet2‘

 

// 注意 : 原始值构造器是一个可失败的构造器, 因为并不是每一个原始值都有与之对应的枚举成员

 

// 如果你试图寻找一个位置 为 11 的枚举成员, 通过原始值构造器返回可选的 Planet2 值将是 nil

 

 

 

// 递归枚举

// 递归枚举是一种枚举类型, 它有一个或多个枚举成员使用该枚举类型的实例作为关联值,使用递归枚举时,编辑器会插入一个间接层, 你可以在枚举成员前加上 indirect 来表示该成员可递归

 

// 例如,下面的例子中, 枚举类型存储了简单的算数表达式

 

enum ArithmeticExpression {

    case number(Int)

    indirect case addition(ArithmeticExpression, ArithmeticExpression)

    indirect case multiplication(ArithmeticExpression,ArithmeticExpression)

}

 

// 你也可以在枚举类型开头加上 indirect 关键字来表明它的所有成员都是可递归的

 

indirect enum ArithmeticExpression2 {

    case number(Int)

    case addition(ArithmeticExpression, ArithmeticExpression)

    case multiplication(ArithmeticExpression, ArithmeticExpression)

}

 

 

// 上面定义的枚举类型可以存储三种算术表达式:纯数字、两个表达式相加、两个表达式相乘。枚举成员addition和multiplication的关联值也是算术表达式——这些关联值使得嵌套表达式成为可能。例如,表达式(5 + 4) * 2,乘号右边是一个数字,左边则是另一个表达式。因为数据是嵌套的,因而用来存储数据的枚举类型也需要支持这种嵌套——这意味着枚举类型需要支持递归。下面的代码展示了使用ArithmeticExpression这个递归枚举创建表达式(5 + 4) * 2

 

let five = ArithmeticExpression.number(5)

let four = ArithmeticExpression.number(4)

let sum = ArithmeticExpression.addition(five, four)

let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

 

Swift 学习- 09 -- 枚举