博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swift 模式匹配
阅读量:5331 次
发布时间:2019-06-14

本文共 4673 字,大约阅读时间需要 15 分钟。

前言

  • 在 Swift 中模式匹配是个重要的概念。

    • 最常用的模式匹配是 switch 语法。
    • 模式匹配非常灵活,在使用 switch 进行一轮模式匹配时,不需要所有的 case 都是同一种风格。

      let i = 5switch i {    case 1:        print("The box is 1")    case 2:        print("The box is 2")    case 3...100:        print("Number in the box is not less than 3 and not more than 100")    default:        print("Guess not to come out")}
  • 很明显 “匹配” 与 “相等” 是不同的,case 中的类型不同时,匹配的标准也不同。

    • case 中只有一个单独的值时,我们可以认为相等就是匹配。
    • case 中是一个范围时,匹配的标准也改变了,因为一个值不可能与一个范围相等,此时我们会认为匹配的标准是该对象存在于该范围中。
  • 实际上很多可以进行模式匹配的对象,本身并不能判等。当你需要对某个对象做模式匹配时,需要提前预设好能够与对象做匹配的数据类型,并且指定匹配的规则。为了实现上述过程需要重载操作符 ~=

    func ~=(lhs: Int, rhs: Int) -> Bool {    ...    }func ~=(lhs: Range
    , rhs: Int) -> Bool { ...}
    • lhs 参数代表 case 可以接受的类型,rhs 代表发起模式匹配的对象。
    • Switch 在表层的模式匹配语法之下封装了这些 ~= 函数,当执行到某个类型的 case 值时会转换成执行对应类型的 ~= 函数,并返回值判断该次匹配知否成功。

1、枚举的模式匹配

  • 在 Swift 中使用枚举的好处是,可以把一些服务器返回的基础类型的值封装成有意义的对象。

    enum TestLevel: Int {    case low    = 0    case middle    case high}
    • 一个普通的枚举类型是不可比较的,有原始值的枚举类型可以做比较,比较时会根据原始值进行比较。
    • 使用上面的简写会分别获得 1 和 2 的原始值。
  • 既然已经决定把服务器返回的状态位封装成一个枚举,那么在数据结构中就不要保留它的原始值,否则你可能不得不写出一个不太好的模式匹配版本。

    let type = TestLevel(rawValue: 0) ?? .lowswitch type {    case .high:        print("Level is high")    case .middle:        print("Level is middle")    case .low:        print("Level is low")}
    • 对枚举做模式匹配时,如果 switchcase 的值覆盖了枚举类型的所有情况时,不需要 default

2、元组的模式匹配

  • 相比于枚举,元组中包含多个数据元素,可以匹配整个元组,也可以匹配元组中的某个数据成员,这是因为 Swift 已经为元组重载了多个版本的 ~= 操作符。

    let tuple = (9527, "xiaoming")switch tuple {    case (1111, "lilei"):                   // 匹配整个枚举        print("Found lilei")    case (2222, _):                         // 只匹配部分元素        print("Num. is 2222")    case (9527, let name):                  // 匹配部分成员,并取出没有参与匹配的元素        print("9527 name is \(name)")    default:        break}
  • 在 Swift 中元组是匿名的,不具备复用的特性,所以经常被当作临时变量保存数据。除了保存数据,元组还可以把一个复杂的 if else 结构封装成模式匹配的格式,使得代码逻辑更加清晰。

    enum Limit: String {    case admin    case guest}func login(limit: Limit, userName: String, password: String) {    switch (limit, userName, password) {        case (.admin, "xiaoming", "abc123"):            print("login success")        case (.admin, _, _):            print("name or password error")        case (.guest, _, _):            print("guest login")    }}
    • 通过元组的封装,把一个逻辑结构的问题转换成了一个数据结构的问题,模式匹配只有一层,判断的顺序一目了然,并且每一个 case 都需要列出 limit, userName, password 三者的具体情况,不会因为 if else 层次的加深而造成逻辑的缺失。

3、if 和 guard 中的模式匹配

  • 除了前面的 switch 语句,Swift 2.0 中为更多的基础语法引入了模式匹配,比如 ifguard 语句。

    if case 可以接受的类型 = 发起模式匹配的对象 {    // 模式匹配成功时执行的代码段}
    guard case 可以接受的类型 = 发起模式匹配的对象 else {    // 模式匹配不成功时执行的代码段    return}// 模式匹配成功时执行的代码段
  • 在判断条件中对基本数据类型使用模式匹配

    let a = 3// 原来的写法if a >= 0 && a <= 5 {    print("include")}
    // 模式匹配的 if case 写法if case 0...5 = a {    print("include")}
    // 模式匹配的 guard case 写法guard case 0...5 = a else {    return}print("include")
  • 也可以在判断条件中对元组使用模式匹配过滤无用信息,结构看起来与 switch 中的 case 的格式类似。

    enum Limit: String {    case admin    case guest}func login(loginTyuple: (limit: Limit, userName: String, password: String)) {    // 先进性黑名单判断    if case (.admin, "lilei", _) = loginTyuple {        return    }    // 在进行正常操作    switch loginTyuple {        case (.admin, "xiaoming", "abc123"):            print("login success")        case (.admin, _, _):            print("name or password error")        case (.guest, _, _):            print("guest login")    }}

4、for 中的模式匹配

  • 在循环中引入模式匹配,则循环只会处理哪些匹配的对象。

    for case 可以接受的类型 in 发起模式匹配的对象集合 {    // 模式匹配成功时执行的代码段}
  • 比如现在有三个用户,我们只对管理员权限的用户进行操作。

    enum Limit: String {    case admin    case guest}let loginArr = [    (Limit.admin, "xiaoming", "abc123"),    (Limit.admin, "lilei", "222"),    (Limit.guest, "hanmeimei", "333")]
    for case let (Limit.admin, name, _) in loginArr {    print(name)}

5、模式匹配中的 where 关键字

  • 我们可以把嵌套的逻辑结构封装成元组,但是并不是所有的逻辑结构都适合封装成元组,这时你可以保留原始的模式匹配格式,然后使用 where 关键字在其上增加逻辑判断。

  • where 语句直接附在 case 语句之后,用来为模式匹配增加匹配条件,where 的优势是保持了模式匹配格式的整齐度,where 可以用于所有的模式匹配中。

    let arr = [    (name: "heianqishi", imdb: 9.0, year: 2008),    (name: "xingjichuanyue", imdb: 8.7, year: 2014),    (name: "jiyisuipian", imdb: 8.5, year: 2000)]
    // 未使用模式匹配的写法for case let (_, imdb, _) in arr {    if imdb > 8.5 {        print(imdb)    }}
    • 使用模式匹配的写法

      // 用在 for 语句中for case let (_, imdb, _) in arr where imdb > 8.5 {    print(imdb)}
      // 用在 if 语句中// Swift 3.0 之前if case 2001...2010 = arr[0].year where arr[0].imdb > 8.5 {    print("21th first high imdb film")}// Swift 3.0 及之后if case 2001...2010 = arr[0].year, arr[0].imdb > 8.5 {    print("21th first high imdb film")}
      // 用在 switch 语句中switch arr[0] {    case (_, let imdb, _) where imdb > 8.0:        print("more than 8.0")    case (_, let imdb, _) where imdb <= 8.0:        print("less than 8.0")    default:        break}

转载于:https://www.cnblogs.com/QianChia/p/8669416.html

你可能感兴趣的文章
[转发]Android 系统稳定性 - ANR(一)
查看>>
HashMap、HashSet源代码分析其 Hash 存储机制
查看>>
原生js实现元素随手指滑动上下滚动
查看>>
线段树【注意事项】
查看>>
Leetcode 134 Gas Station
查看>>
iptables
查看>>
TF-IDF与余弦相似性的应用(一):自动提取关键词
查看>>
“随时、随性、随遇、随缘、随喜”
查看>>
linux下apache和tomcat整合
查看>>
【结构型模式】《大话设计模式》——读后感 (9)牛市股票还会亏钱?——外观模式...
查看>>
DNN-HMM
查看>>
MQ java 基础编程(一)
查看>>
Asp.net中IsPostBack的实现原理
查看>>
微信小程序 - 配置普通二维码跳小程序
查看>>
es5~es6
查看>>
mongoDB - 安装
查看>>
Python学习1,Python的六大数据类型
查看>>
JavaEE
查看>>
学习MFC创建界面
查看>>
Building QGIS from source - step by step (开发文档翻译1)
查看>>