Swift学习之枚举

6 分钟阅读

定义与调用

枚举概念类似C语言,语法不同,而且可以不用定义类型(C语言为int型),举例如下:

enum CompassPoint {
  case North
  case South
  case East
  case West
}

也可以定义成一行,用,隔开:

enum CompassPoint {
  case North,South,East,West
}

调用方法如下:

var directionToHead = CompassPoint.West
//后面赋值时CompassPoint可以省略
directionToHead = .East

//可以放在switch中进行匹配
switch directionToHead {
case .East:
  print("Direction East")
default:
  print("Not East Direction")
}
//输出"Direction East"

原始值(Raw Values)

1.枚举类型也可以指定原始类型,如下例子:

//原始值类型为Character
enum ASCIIControlCharacter: Character {
  case Tab = "\t"
  case LineFeed = "\n"
  case CarriageReturn = "\r"
}

let tabChar = ASCIIControlCharacter.Tab.rawValue
//此时tabChar="\t"

2.当原始值类型是整型或者String时,存在隐式赋值; 整型第一个原始值默认为0,后续值默认依次增1;

enum CompassPoint:Int{
  case North=1,South,East,West
}
let sunsetDirection = CompassPoint.West.rawValue
// sunsetDirection 值为 4

String默认原始值为对应成员的名称:

enum CompassPointS: String {
  case North, South, East, West
}
let sunsetDirection = CompassPointS.West.rawValue
// sunsetDirection 值为 "West"

3.原始值初始化枚举变量,该变量为可选值,如下例中的CompassPoint(rawValue: 2)

if let somePoint = CompassPoint(rawValue: 2) {
  switch somePlanet {
  case .East:
    print("Direction East")
  default:
    print("Not Direction East")
  }
} else {
  print("There isn't a correct direction")
}
// 输出 "Not Direction East"

相关值(Associated Values)

可以理解成枚举类型有额外的属性,如下举例

//商品有数字码和字串码,数字码UPCA附加4个数值,字串码QRCode附加1个字串
enum Barcode {
  case UPCA(Int, Int, Int, Int)
  case QRCode(String)
}

//注意赋值顺序,UPCA和QRCode只存其一
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
  print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
  print("QR code: \(productCode).")
}
// 输出 "QR code: ABCDEFGHIJKLMNOP."

当所有相关值提取成变量或常量,可以整体提取,上例第一个case可以简写如下:

case let .UPCA(numberSystem, manufacturer, product, check)

递归枚举(Recursive Enumerations)

可以理解成相关值得扩展,相关值类型不确定,根据实际传入值而定,这样就可以方便扩展,如下:

//Addition和Multiplication中的两个相关值不是类型
enum ArithmeticExpression {
  case Number(Int)
  indirect case Addition(ArithmeticExpression, ArithmeticExpression)
  indirect case Multiplication(ArithmeticExpression, ArithmeticExpression)
}

//由于不确定类型,下面left和right可以是任意支持+和*运算的类型
func evaluate(expression: ArithmeticExpression) -> Int {
  switch expression {
  case .Number(let value):
    return value
  case .Addition(let left, let right):
    return evaluate(left) + evaluate(right)
  case .Multiplication(let left, let right):
    return evaluate(left) * evaluate(right)
  }
}

// 计算 (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))
print(evaluate(product))
// 输出 "18"

个人看法:递归枚举有点泛型的味道,但是极难理解和使用,不建议写这样的语句编程。

定义方法

具体方法与结构体中的方法概念相同,以下举例:

enum TriStateSwitch {
  case Off, Low, High
  mutating func next() {
    switch self {
    case Off:
      self = Low
    case Low:
      self = High
    case High:
      self = Off
    }
  }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight 现在等于 .High
ovenLight.next()
// ovenLight 现在等于 .Off