七、Swift 枚举 Enumerations
1. 概述
Swift的枚举与C类似,在C中,编译器会为枚举的每一个成员提供一个默认的整型值(假设为raw),默认从0开始,不断累加。
而在Swift中,你可以不提供raw(与C不同,如果你不自己定义raw,编译器不会自动提供),或者将raw指定为任意类型,如string, character, integer, floating-point。枚举成员可以独自与任何类型进行关联,而不关心其他枚举成员。
2. 枚举的语法
按如下方式定义一个枚举:
enum SomeEnumeration { // enumeration definition goes here }
可以这么写:
enum CompassPoint { case North case South case East case West }
也可以写成一行:
enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
在Swift中,每种类型都用大写字母开头,如上面的SomeEnumeration 和CompassPoint ,枚举的名字使用单数形式进行定义,而不是复数形式,所以访问起来不言而喻:
var directionToHead = CompassPoint.West
如果编译器可以推断出 directionToHead 的类型为 CompassPoint. ,可以使用简写形式:
directionToHead = .East
3. 枚举与Swift语句混合使用 Matching Enumeration Values with a Switch Statement
例如:
directionToHead = .South switch directionToHead { case .North: println("Lots of planets have a north") case .South: println("Watch out for penguins") case .East: println("Where the sun rises") case .West: println("Where the skies are blue") } // prints "Watch out for penguins"
如果没有匹配的 case,添加default:
let somePlanet = Planet.Earth switch somePlanet { case .Earth: println("Mostly harmless") default: println("Not a safe place for humans") } // prints "Mostly harmless"
4. 关联值 Associated Values
为枚举成员设置关联值,可以为枚举成员提供额外的信息。
举个栗子,设想一个库存跟踪系统想要通过两种不同的条形码来跟踪产品。一些产品用UPC-A格式的一维条形码标识的,使用0到9的数字。每个条形码当中有 一个标识“数字系统“的数字,然后是10个“标识符"数字,最后边一个用来做“检查”的数字,以确保这个条形码被正确的扫描识别:
另一些产品是用QR编码格式的二维码标识的,这种条形码可以使用任何ISO 8859-1的字符而且最大可以编码一个2953字符长度的字符串:
如果能够用一个有三个整型的元组来存储UPC-A格式的条形码,然后用一个可以存储任意长度的字符串来存储QR格式的条形码,那么对于一个库存跟踪系统来说,将会是再便捷不过的了。
在Swift中,我们可以如下定义:
enum Barcode {// 条形码 case UPCA(Int, Int, Int, Int) case QRCode(String) }
这样一来可以用任意其中一个类型来生成一个新的条形码了:
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
同样的产品还可以被赋值为另一个条形码类型:
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
在这一点上,原来的Barcode.UPCA以及关联到的整型值被一个新类型Barcode.QRCode以及与其关联的字符串给替换了。Barcode 类型的不可变变量以及可变变量可以存储.UPCA或者.QRCode类型(同时还有与其相关联的值),但是每次都只能存储这两个类型当中的一个。
同样,这两个不同的类型可以用Switch语句来做检查。同时,在switch语句中他们相关联的值也可以被获取到。你可以把关联的值当做不可变变量(用let来开头),或者可变变量(用var开头)以在switch的控制体当中使用。
switch productBarcode { case .UPCA(let numberSystem, let manufacturer, let product, let check): println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).") case .QRCode(let productCode): println("QR code: \(productCode).") } // prints "QR code: ABCDEFGHIJKLMNOP."
如果一个枚举成员关联的所有值都被当做不可变变量或者可变变量来使用,那么你可以在成员名称之前只放一个let或者var来达到目的,简要示例:
switch productBarcode { case let .UPCA(numberSystem, manufacturer, product, check): println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).") case let .QRCode(productCode): println("QR code: \(productCode).") } // prints "QR code: ABCDEFGHIJKLMNOP."
5. Raw Values
在上一节当中条形码的例子展示了一个枚举类型的成员怎么声明他们可以存储不同类型的关联值。
另一种设置关联值的方式是给枚举成员设置预设值 prepopulated (我们叫他 Row Values),这些值的类型都是相同。
原话是:As an alternative to associated values, enumeration members can come prepopulated with default values (called raw values), which are all of the same type.
这里有一个枚举成员存储一个ASCII值的例子:
enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" case CarriageReturn = "\r" }
在第四小节中,是在创建枚举的实例时设置关联值,每次创建的实例的关联值都可以不同
而 Row Values 是在枚举定义时就为枚举成员设置了预设值。Row Values可以是strings, characters, integer, floating-point。每一个Row Value 必须唯一。
当设置预设值为整形时,如果你没有指定后面的成员的预设值的话,预设值会自动增加。
下面例子中枚举的预设值是自动增加的:
enum Planet: Int { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
let earthsOrder = Planet.Earth.rawValue // earthsOrder is 3
6. 通过rawValue进行初始化 Initializing from a Raw Value
比如:
let possiblePlanet = Planet(rawValue: 7) // possiblePlanet is of type Planet? and equals Planet.Uranus
注意:rawValue是一个failable initializer,因为不是每一个rawValue都会返回一个枚举成员。
例如:
let positionToFind = 9 if let somePlanet = Planet(rawValue: positionToFind) { switch somePlanet { case .Earth: println("Mostly harmless") default: println("Not a safe place for humans") } } else { println("There isn't a planet at position \(positionToFind)") } // prints "There isn't a planet at position 9"
http://c.biancheng.net/cpp/html/2426.html