Swift之枚举enum的语法和功能

Posted ╰つ栺尖篴夢ゞ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift之枚举enum的语法和功能相关的知识,希望对你有一定的参考价值。

一、前言

  • 枚举是为一组相关值定义的一个通用类型,Swift 枚举的功能非常强大,使它比 OC 的枚举应用于更广泛的场景。
  • 在本文,我们去了解 enum 的语法和能力。

二、枚举语法

  • 使用 enum 关键字引入枚举,其整个定义放在一对大括号内:
enum CompassPoint 
    case north
    case south
    case east
    case west

  • 与 C 和 Objective-C 不同,Swift 的枚举成员在创建时不会被赋予一个默认的整型值。

三、枚举成员遍历

  • 令枚举遵循 CaseIterable 协议,Swift 会生成一个 allCases 属性,用于返回枚举中所有成员的集合。
enum Beverage: CaseIterable 
    case coffee, tea, juice


for beverage in Beverage.allCases 
    print(beverage)


// coffee
// tea
// juice
关联值
  • 关联值是将附加信息附加到枚举成员的一种非常好的方式。Swift 枚举可以存储任意类型的关联值,例子如下:
enum Barcode 
    case upc(Int, Int, Int, Int)
    case qrCode(String)

  • 上面的代码定义一个名为 Barcode 的枚举类型,其中一个成员 upc 具有(Int, Int, Int, Int) 类型的关联值,另一个成员 qrCode 具有 String 类型的关联值。可以通过模式匹配来访问关联值,例子如下:
var productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
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.”

四、原始值

  • 枚举成员可以被默认值预填充,这些默认值被称为原始值,注意:原始值的类型必须相同。
enum ASCIIControlCharacter: Character 
    case tab = "\\t"
    case lineFeed = "\\n"
    case carriageReturn = "\\r"

  • 默认情况下,Swift 只支持下面4种类型的枚举值:整型、浮点数、字符串、布尔值。如果要支持更多类型的枚举值,需要实现指定的协议,这个在后面的文章中会讲到。

五、原始值的隐式赋值

  • 在使用的原始值是整数或字符串类型时,Swift 可以为你自动赋值。
  • 当使用的原始值是整数时,隐式赋值的值会一次增加1。如果第一个枚举成员没有设置原始值,其默认原始值是 0。
enum Planet: Int 
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune

// Plant.mercury 的显式原始值为 1,Planet.venus 的隐式原始值为 2,依此类推。
  • 当使用字符串作为枚举成员的原始值时,每个枚举成员的隐式原始值是该成员的名字。
enum CompassPoint: String 
    case north, south, east, west


// CompassPoint.south 拥有隐式原始值 south,依此类推。
  • 可以使用 rawValue 属性访问枚举成员的原始值:
let earthsOrder = Planet.earth.rawValue
// earthsOrder 值为 3

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection 值为 "west"

六、使用原始值初始化枚举实例

  • 如果在定义枚举时使用了原始值,那么会自动生成一个初始化方法,这个方法有一个 rawValue 参数,参数类型即为原始值类型:
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet 类型为 Planet? 值为 Planet.uranus
  • 原始值构造器是一个可失败的构造器,因为并不是每一个原始值都有一个与之对应的枚举成员,因此其返回类型是可选类型。

七、递归枚举

  • 递归枚举是一种枚举类型,它的一个或多个成员使用该枚举类型作为关联值。在枚举成员前加上 indirect 关键字表示该成员可递归:
enum ArithmeticExpression 
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)

也可以在枚举类型开头加上 indirect 来表明其所有成员都可递归:

indirect enum ArithmeticExpression 
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)

  • 其使用如下:
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

func evaluate(_ expression: ArithmeticExpression) -> Int 
    switch expression 
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right) // (5 + 4) * 2
    


print(evaluate(product))

// 打印“18”

八、嵌套枚举

  • Swift 中允许枚举嵌套,在使用时,需要确保一个枚举类型是从属于另一个枚举类型的,否则会引起语义混乱。下面看一个例子:
enum Character 
  enum Weapon 
    case Bow
    case Sword
    case Lance
    case Dagger
  
  enum Helmet 
    case Wooden
    case Iron
    case Diamond
  
  case Thief
  case Warrior
  case Knight


// 通过层级来访问嵌套的枚举成员
let character = Character.Thief
let weapon = Character.Weapon.Bow
let helmet = Character.Helmet.Iron
  • 访问嵌套枚举成员时,不必每次都输入这么长的层级来访问,可以使用便捷方法直接访问,如下:
func strength(of character: Character, 

              with weapon: Character.Weapon, 

              and armor: Character.Helmet) 



strength(of: .thief, with: .bow, and: .wooden)

九、包含枚举

  • 也可以在结构或类中嵌入枚举。继续前面的例子:
struct Character 
    enum CharacterType 
     case thief
     case warrior
     case knight
   

   enum Weapon 
     case bow
     case sword
     case lance
     case dagger
   

   let type: CharacterType
   let weapon: Weapon


let warrior = Character(type: .warrior, weapon: .sword)

十、方法和属性

  • Swift 枚举类型可以附加方法和属性:
enum Transportation 
   case car(Int)
   case train(Int)

    func distance() -> String 
     switch self 
     case .car(let miles): return "\\(miles) miles by car"
     case .train(let miles): return "\\(miles) miles by train"
     
   

  • 与结构或类类型的主要区别在于,可以在方法中使用 self 来计算输出。

十一、“属性”添加限制

  • Swift 中不允许添加存储属性,下面的代码会编译报错:
enum Device 
   case iPad
   case iPhone
   
   let introduced: Int // Enums must not contain stored properties

  • 应该使用计算属性,如下:
enum Device 
    case iPad,
    case iPhone

    var introduced: Int 
        switch self 
        case .iPhone: return 2007
        case .iPad: return 2010
     
  

十二、静态方法

  • 静态方法是可以通过类型名称而不是类型的特定实例调用的方法。例子如下:
enum Device 
    static var newestDevice: Device 
        return .appleWatch
    

    case iPad,
    case iPhone
    case appleWatch

十三、可变方法

  • 通过 mutating 关键字将方法声明为可变方法,在可变方法中可以修改 self 实例,例子如下:
enum TriStateSwitch 
    case off, low, bright
    mutating func next() 
        switch self 
        case .off:
            self = low
        case .low:
            self = .bright
        case high:
            self = off
        
    


var ovenLight = TriStateSwitch.low

ovenLight.next()
// ovenLight is now equal to .bright

ovenLight.next()
// ovenLight is now equal to .off

以上是关于Swift之枚举enum的语法和功能的主要内容,如果未能解决你的问题,请参考以下文章

Swift具体解释之六----------------枚举结构体类

python之枚举类型

Android之使用枚举利弊及替代方案

iOS开发-Swift进阶之协议Protocol!

Swift-细说枚举(Enum)

Swift枚举使用String值获取Int Enum的值