美文网首页
#8 swift 枚举类型

#8 swift 枚举类型

作者: JamesSawyer | 来源:发表于2018-08-29 00:45 被阅读24次

    swift中的枚举( Enumerations )真的是太灵活了,感觉自己已经驾驭不了这匹野马了😭。

    swift中的枚举特点:

    • 一等公民(first-class citizen)
    • 枚举是值类型,如果需要改变其成员值,需要通过 mutating 关键词
    • 支持类,结构体中所支持的计算属性(computed properties),就是其它语言中的 getter, setter 方法
    • 支持实例方法,提供枚举值相关联的功能
    • 还可以定义构造函数(mmp,太难了)
    • 还可以在原始实现的基础上扩展其功能
    • 可以遵循协议(protocols) 提供标准的功能
    • 和C以及OC不同的是,swift中的枚举成员在创建的时候不会被赋予一个默认的整型值
    • 其中涉及到的关键词和属性有: indirectCaseIterable, allCase, rawValue
    • 涉及到的知识点: 关联值, 原始值,递归枚举

    1.语法

    使用 enum 关键词定义枚举类型,这个和其它语言一致 例如

    typescript中定义枚举:

    enum Direction {
      Up, // 默认的赋值为0,底下的依次 +1
      Down,
      Left,
      Right
    }
    

    swift中: 使用 case 关键词来定义一个新的枚举成员

    enum Direction {
      // Up,Down...也称之为 成员值
      case Up  // 此处不会默认的赋值 0
      case Down
      case Left
      case Right
    }
    
    // 等价于
    enum Direction {
      case Up, Down, Left, Right
    }
    

    使用:

    var direction = Direction.Up
    
    // 或者
    var direction: Direction = .Up
    

    2.用Switch语句匹配枚举值

    可以使用switch匹配单个枚举值

    enum Direction {
      case Up, Down, Left, Right
    }
    var direction: Direction = .Up
    
    switch direction {
    case .Up:
      print("向上")
    case .Down:
      print("向下")
    case .Left:
      print("向左")
    case .Right:
      print("向右")
    // default语句可写 可不写
    default:
      print("其它方向")
    }
    

    3.关联值(Associated Values)

    作用:

    • 将其它类型的关联值和成员值一起进行存储,这样可以连同成员值一起存储额外的自定义信息
    • 每次在代码中使用该枚举成员时,还可以修改这个关联值

    示例:一种商品有2种编码方式进行追踪:

    1. 按照 1-5-5-1 格式的数字('1' 表示1位数字 '5' 表示5位数字)表示商品的UPC一维条形码
    2. 使用字符串的形式QR码
    enum Barcode {
      // 理解方式
      // 成员值是具有 (Int, Int, Int, Int) 类型相关联值的upc
      case upc(Int, Int, Int, Int) // 一维条形码
      // 具有 String 类型关联值的 qrCode
      case qrCode(String) // QR码
    }
    
    // 使用
    // 定义一个商品的一维条形码
    var productBarcode = Barcode.upc(8, 89201, 28993, 1)
    // 也可以定义为一个QR码
    prodictBarcode = .qrCode("ABCDEFGHEISLDK")
    
    // 配合switch
    switch productionBarcode {
      // 其中 let 表示提取变量 这个可以参考控制流switch章节
    case let .upc(numberSystem, manufacturer, product, check):
      print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
    case let .qrCode(productCode):
      print("QR code: \(productCode)")
    }
    

    4.迭代枚举类型(Iterating over Enumeration)

    有时候我们可能需要将枚举中所有的case情况组成一个集合,可以让枚举类型扩展CaseIterable 协议。

    另外swift通过 allCases 属性暴露了枚举类型中所有case 的集合:
    注意 Xcode 10.0+版本才支持这个属性

    // 扩展 CaseIterable 协议
    enum Beverage: CaseIterable {
      case coffee, tea, juice
    }
    
    // allCases 属性暴露了枚举中cases集合
    let numberOfChoices = Beverage.allCases.count // 3
    
    // 使用for-in进行迭代
    for beverage in Beverage.allCases {
      print(beverage)
    }
    // coffee
    // tea
    // juice
    

    5.原始值(Raw Values)

    作为关联值的替代选择,枚举成员可以被默认值(也称为原始值)预填充,这些原始值的类型必须相同

    原始值的理解: 即定义枚举的时候,把枚举的类型也定义了,比如 enum Color: String, 定义其类型为 String 类型

    和关联值的区别:

    • 关联值是创建一个局域枚举成员的常量或变量时才设置值,关联值可以变化
    • 原始值针对特定的枚举成员类型,原始值会预先填充值,并且始终不变

    示例:使用ASCII码作为原始值的枚举

    // 这里使用Character类型作为原始值类型
    // 还可以是 字符串,整型或者浮点类型
    enum ASCIIControlChar: Character {
      case tab = "\t"
      case lineFeed = "\n"
      case carriageReturn = "\r"
    }
    

    原始值的隐式赋值

    当原始值类型为整型或者字符串类型时,不需要显式的给每个枚举成员设置原始值,swift会自动的为你赋值

    enum Direction: Int {
      // 依次 +1 进行类推
      case Up = 1, Down, Left, Right
    }
    

    使用 rawValue 属性可以访问枚举成员的原始值:

    var left: Direction = .Left
    // 原始值
    left.rawValue // 3
    

    字符串类型隐式的为该枚举成员的名称

    enum CompassPoint: String {
      case ease, south, west, north
    }
    
    // 使用 rawValue
    let north = CompassPoint.north.rawValue // "north"
    

    使用原始值初始化枚举类型

    如果枚举类型使用了原始值,自动获取一个初始化方法(呵呵,什么鬼),这个方法接收一个 rawValue 的参数,参数类型即为原始值类型,返回值则是枚举成员或 nil

    另外,原始值构造器是一个可失败构造器(failable initializer)

    例如,调用构造器创建一个新的枚举实例

    enum Direction: Int {
      // 依次 +1 进行类推
      case Up = 1, Down, Left, Right
    }
    
    // 使用构造器,参数为rawValue 创建一个枚举实例
    let possibleDirection = Direction(rawValue: 3)
    // possibleDirection 的类型为 Direction? (可选类型)
    // 值为 Direction.Left
    
    // 如果不存在该值,这表示构造失败
    let antherDirection = Direction(rawValue: 10)
    // possibleDirection 的类型为 Direction
    // 值为 nil
    

    6.递归枚举

    特点:

    • 递归枚举是一种枚举类型
    • 它有一个或多个枚举成员使用 枚举类型的实例作为关联值
    • 编译器会插入一个间接层
    • 可以在枚举成员前加上 indirect 来表示该成员可递归
    • 也可以在枚举类型的开头加上 indirect 关键词表示所有枚举成员都可递归
    // 部分枚举成员可递归枚举
    // 上面示例中 3个成员 都是 关联值
    enum ArithExpression {
      case number(Int)
      // 使用一个或多个枚举成员的实例作为关联值
      // 使用 indirect 关键词
      indirect case addition(ArithExpression, ArithExpression)
      indirect case multi(ArithExpression, ArithExpression)
    }
    
    // 在 enum 前加上 'indirect' 表示所有枚举成员都可递归枚举
    indirect enum ArithExpression {
      case number(Int)
      case addition(ArithExpression, ArithExpression)
      case multi(ArithExpression, ArithExpression)
    }
    
    // 使用
    let five = ArithExpression.number(5)
    let four = ArithExpression.number(4)
    let sum = ArithExpression.addition(five, four)
    let multiResult = ArithExpression.multi(sum, ArithExpression.number(2))
    

    要操作具有递归性质的数据结构,使用递归函数事一种直接的方式:

    func evaluate(_ expression: ArithExpression) -> Int {
      switch expression {
      case let .number(value):
        return value
      case let .addition(left, right):
        return evaluate(left) + evaluate(right)
      case let .multi(left, right):
        return evaluate(left) * evaluate(right)
      }
    }
    

    感觉这个这么复杂,估计用到的地方也比较少,了解即可

    8.使用mutating 改变枚举成员的值

    因为枚举类型是值类型,赋值一般都是通过拷贝的方式,所以原来的值不会改变,swift中提供了 mutating 关键词用来改变值类型的值

    // 风扇开关
    // 有3个档位 Off, Low, High
    // next 方法用来 表示其下一档位
    enum FanSwitch {
      case Off, Low, High
      mutating func next() {
        switch self {
        case .Off:
          self = .Low
        case .Low:
          self = .High
        case .High:
          self = .Off
        }
      }
    }
    
    // 定义为 Low 档位
    var fan = FanSwitch.Low
    
    fan.next()  // High
    fan.next()  // Off
    fan.next()  // Low
    

    8.枚举是值类型

    enum CompassPoint {
        case North, South, East, West
    }
    var currentDirection = CompassPoint.West
    // 将上面的枚举实例赋值给另一个常量 通过拷贝的方式
    let rememberedDirection = currentDirection
    // 改变原来的枚举变量的值
    currentDirection = .East
    
    // 并不会影响到其赋值的值
    if rememberedDirection == .West {
        print("The remembered direction is still .West")
    }
    // 打印 "The remembered direction is still .West"
    

    9.关于枚举其它

    可选类型是一个泛型枚举

    其结构大致如下

    enum Optional<T> {
      case None
      case Some(T) // 关联值
    }
    
    // 示例1
    var str: String? = nil
    // 等价于
    var str = Optional<String>.None
    
    // 示例2
    var str2: String? = "Holo"
    // 等价于
    var str2 = Optional<String>.Some("Holo")
    
    // 对于可选类型 需要解包
    var showStr = str2!
    // 这个过程等价于
    switch str2 {
      case Some(let value):
        showStr = value
      case None:
        // 解包发生异常
    }
    

    枚举内部访问case

    enum Turn {
      case left
      case right
      var reminder: String {
        switch self {
        case .left:
          return "左转"
        case .right
          return "右转"
        }
      }
    }
    

    类型属性(静态属性或者类属性)

    enum SomeEnum {
      static var storedTypeProty = 10
      static var computedTypeProperty: Int {
        // get, set 方法
      }
    }
    

    相关文章

      网友评论

          本文标题:#8 swift 枚举类型

          本文链接:https://www.haomeiwen.com/subject/hxgcwftx.html