【iOS】swift 枚举
枚举语法
你可以用enum开始并且用大括号包含整个定义体来定义一个枚举:
- enum SomeEnumeration {
- // 在这里定义枚举
- }
- enum CompassPoint {
- case North
- case South
- case East
- case West
- }
注意:与C或者Objective-C不同的是,在Swift语言中枚举类型的成员初始的时候不会被默认赋值成整数值,在CompassPoint这个例子中,North, South, East, West默认不会隐式的等于0,1,2,3。取而代之的是不同的枚举成员将要用什么类型以及赋值什么值都是可以自己控制的,可以在定义CompassPoint这个枚举的时候指定.多个成员还可以用一行来定义,他们之间用逗号分割:
- enum Plant{
- case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
- }
- var directionToHead = CompassPoint.West
- directionToHead = .East
使用Switch语句来匹配枚举值
你可以通过switch语句来访问单独的某个枚举值:
- 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")
- }
- // 输出"Watch out for penguins”
就和在控制流程那一章所讲,一个switch语句被用到判断枚举值的时候,必须要包括所有的枚举成员。假设.West被忽略了,将会导致编译出错,因为它没有考虑到枚举的所有的枚举成员,我们需要全面性的确保枚举的所有成员不被忽略掉.
如果给考虑每个枚举的成员不合适,你可以提供一个default来覆盖其他没有明确处理的成员:
- let somePlanet = Planet.Earth
- switch somePlanet {
- case .Earth:
- println("Mostly harmless")
- default:
- println("Not a safe place for humans")
- }
- // 输出 "Mostly harmless"
关联值
在上一节的示例中显示了一个枚举的成员是如何在自己的权利界定(和类型)的值。你可以设置一个常量或变量的值为Planet.Earth ,然后检查这个值。然而,如果在保留成员值的同时能够存储其它类型的关联值将会变得更有意义。这使您能够在保存成员值的同时存储额外的自定义信息,并且允许每次你在代码中使用这些成员值的时候改变这些关联值。在Swift中当你定义一个枚举成员的时候,你可以给他关联任何的类型,而且如果需要的话每个成员可以有不同的关联类型。枚举类型的这个特性和其他语言当中的辨别联合,标记联合或者变体很像。举个例子,设想一个库存跟踪系统想要通过两种不同的条形码来跟踪产品。一些产品用UPC-A格式的一维条形码标识的,使用0到9的数字。每个条形码当中有一个标识“数字系统“的数字,然后是10个“标识符"数字,最后边一个用来做“检查”的数字,以确保这个条形码被正确的扫描识别:
![](http://c.biancheng.net/cpp/uploads/allimg/140617/1-14061GA113P6.png)
另一些产品是用QR编码格式的二维码标识的,这种条形码可以使用任何ISO 8859-1的字符而且最大可以编码一个2953字符长度的字符串:
![](http://c.biancheng.net/cpp/uploads/allimg/140617/1-14061GA132T0.png)
如果能够用一个有三个整型的元组来存储UPC-A格式的条形码,然后用一个可以存储任意长度的字符串来存储QR格式的条形码,那么对于一个库存跟踪系统来说,将会是再便捷不过的了。
在Swift语言中,一个可以定义两个格式的产品条形码的枚举看起来是这样的:
- enum Barcode {
- case UPCA(Int, Int, Int)
- case QRCode(String)
- }
这个定义不会生成任何的整型或者字符串值,他只是定义了当一个不可变变量或者变量等于Barcode.UPCA或者Barcode.QRCode的时候它被关联的值的类型
这样一来可以用任意其中一个类型来生成一个新的条形码了:
- var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
同样的产品还可以被赋值为另一个条形码类型:
- productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
同样,这两个不同的类型可以用Switch语句来做检查。同时,在switch语句中他们相关联的值也可以被获取到。你可以把关联的值当做不可变变量(用let来开头),或者可变变量(用var开头)以在switch的控制体当中使用。
- switch productBarcode { case .UPCA(let numberSystem, let identifier, let check): println("UPC-A with value of \(numberSystem), \(identifier), \(check).") case .QRCode(let productCode): println("QR code with value of \(productCode).") }
- switch productBarcode {
- case let .UPCA(numberSystem, identifier, check):
- println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
- case let .QRCode(productCode):
- println("QR code with value of \(productCode).")
- }
- // 输出 "QR code with value of ABCDEFGHIJKLMNOP.”
原始值
在上一节当中条形码的例子展示了一个枚举类型的成员怎么声明他们可以存储不同类型的关联值。不同于关联值,枚举类型的成员还可以预设置默认值(我们叫他原始值),这些值的类型是相同的。这里有一个枚举成员存储一个ASCII值的例子:
- enum ASCIIControlCharacter: Character {
- case Tab = "\t"
- case LineFeed = "\n"
- case CarriageReturn = "\r"
- }
请注意,原始值与关联值不同。原始值应该是在你定义枚举的代码中被设置为预填充值的,就像上述三个ASCII码。对于一个特定的枚举成员的原始值始终是相同的。关联值是当你创建一个基于枚举的成员的新的常量或变量的时候设置的,并且每次都可以是不同的。
原始值可以是字符串,字符或者其他任何的整型或者浮点型等数字类型。每个原始值在他属的枚举类型定义的时候都应该是不同的。如果原始值是整数类型,那么当其他枚举成员没有设置原始值的时候,他们的原始值是这个整型原始值自增长设置的。
下边这个枚举类型是对之前的Plant枚举类型的改良,新的枚举类型有一个整型的原始值来标识他们在距离太阳的顺序:
- enum Planet: Int {
- case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
- }
可以通过枚举成员的toRaw()方法来获取他的原始值:
- let earthsOrder = Planet.Earth.toRaw()
- //eathsOrder is 3
- let possiblePlanet = Planet.fromRaw(7)
- // possiblePlanet is of type Planet? and equals Planet.Uranus”
如果你尝试通过原始值9来寻找他对应的Planet,那么fromRaw()返回给你的非强制Planet类型将会是nil:
- let positionToFind = 9
- if let somePlanet = Planet.fromRaw(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)")
- }
- // 输出 "There isn't a planet at position 9”