首页 > 代码库 > [Swift]Day09:枚举

[Swift]Day09:枚举

枚举

相关值 - Associated Values

Swift 中的相关值有点像是 F# 中的 Discriminated Unions,它允许在枚举中存储额外的数据。

比如下面这个 Barcode 的例子。枚举类中定义了两种条形码,一种是普通的条形码 UPCA ,存储四个 Int 值;另一种是二维码 QRCode ,存储一个字符串的值:

enum Barcode {
    case UPCA(Int, Int, Int, Int)
    case QRCode(String)
}

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

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

这个挺有意思,如果我们要比较两个枚举变量,比如 code1 == code2 ,结果是相等还是不等呢?

答案是:都不对。Xcode会报错告诉你 == 符号无法调用。我们可以自定义运算符解决这个问题:

func ==(a:Barcode, b:Barcode) -> Bool {
    switch(a) {

    case let .UPCA(a1,b1,c1,d1):
        switch(b) {
        case let .UPCA(a2,b2,c2,d2):
            return (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
        default:
            return false
        }

    case let .QRCode(a1):
        switch(b) {
        case let .QRCode(a2):
            return a1 == a2
        default:
            return false
        }
    }
}

enum Barcode {
    case UPCA(Int, Int, Int, Int)
    case QRCode(String)
}

var code1 = Barcode.UPCA(8, 85909, 51226, 3)
var code2 = Barcode.UPCA(8, 85909, 51226, 4)

code1 == code2  // false

如果没有相关值是可以直接比较的:

enum Numbers: Int {
    case One = 1, Two, Three, Four, Five
}
var possibleNum1 = Numbers.Three
var possibleNum2 = Numbers.Three
println(possibleNum1 == possibleNum2) // true

原始值 - Raw Values

我们可以给枚举类型的成员用默认值填充,比如下面这个例子,成员的类型为 Character :

enum ASCIIControlCharacter: Character {
    case Tab = "\t"
    case LineFeed = "\n"
    case CarriageReturn = "\r"
}

原始值可以是 StringCharacterIntFloat,但是只有 Int 可以自增。使用 toRaw 可以访问该枚举成员的原始值:

ASCIIControlCharacter.Tab.rawValue  // rawValue = http://www.mamicode.com/t

也可以用 fromRaw 从原始值转换成枚举成员,注意返回的是 .Some ,因为不一定能转换成功:

var a = ASCIIControlCharacter(rawValue: "\t")
a?.rawValue // {Some "\t"}

遍历

我们可以通过 allValues 遍历枚举类型的所有成员:

enum ProductCategory : String {
     case Washers = "washers", Dryers = "dryers", Toasters = "toasters"

     static let allValues = [Washers, Dryers, Toasters]
}

for category in ProductCategory.allValues{
     //Do something
}

用处

用好枚举类型可以有效的提高代码的可读性,比如我们在 prepareForSegue 中经常需要对 segue.segueIdentifier进行比较,如果纯粹的进行字符串比较显得很生硬,不妨在外面套上一层枚举类型,像这样:

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if let identifier = SegueIdentifier.fromRaw(segue.identifier) {
        switch identifier {
        case .OtherScreenSegue1:
            println("Going to other screen 1")
        case .OtherScreenSegue2:
            println("Going to other screen 2")
        case .OtherScreenSegue3:
            println("Going to other screen 3")
        default:
            println("Going somewhere else")
        }
    }
}

同理,也可以用在 NSNotificationCenter 里。

其他

发现一个挺好的网站:SwiftExamples,通过例子演示 Swift 的各种语法,如果一时半会的忘了某个语法可以去看一看。


References

  • Enumerations
  • AdvancedOperators
  • How to test equality of Swift enums with associated values
  • How to enumerate an enum with String type?
  • Replace Magic Strings with Enumerations in Swift

[Swift]Day09:枚举