#8 swift 枚举类型

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 方法
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,745评论 2 9
  • 本章将会介绍 闭包表达式尾随闭包值捕获闭包是引用类型逃逸闭包自动闭包枚举语法使用Switch语句匹配枚举值关联值原...
    寒桥阅读 1,558评论 0 3
  • 枚举为一组相关的值定义了一个共同的类型,使你可以在你的代码中以类型安全的方式来使用这些值。 如果你熟悉 C 语言,...
    雨影阅读 344评论 0 0
  • 家人们,下午好! 今天周一,2位同学没有穿礼服,下次不单独通知了,每周一都要穿礼服,天气热的话,外套不要穿来了。 ...
    赵诚彬阅读 562评论 0 0
  • 快乐的孩童 北颖 整整一个小时, 我的外孙都在开心戏水。 他用小碗取河里的水, 倒进小桶里, 又倒掉, 又再一次倒...
    北颖阅读 175评论 0 0