前言

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

    • 最常用的模式匹配是 switch 语法。

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

      let i = 5
      
      switch 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<Int>, 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) ?? .low
    
    switch 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
      }

Swift 模式匹配的更多相关文章

  1. Swift中switch强大的模式匹配

    不少人觉得Swift中switch语句和C或C++,乃至ObjC中的差不多,此言大谬! 让本猫带领大家看一下Swift中switch语句模式匹配的威力. 所谓模式匹配就是利用一定模式(比如couple ...

  2. swift模式和模式匹配

    模式和模式匹配 模式: 代表单个或者复合值得结构,也就是说模式不是一个特定的值,它是一种抽象的结构,[一句话,不是特指,是泛指].这样就可以用模式来匹配各种各样的值. 例如:(x,y)可以匹配元祖(1 ...

  3. swift 高级模式匹配 if case

    let age = 22 let sex = "girl" if (sex == "girl" && age >= 18 &&am ...

  4. swift 的枚举、结构体、类

    一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...

  5. swift错误和异常处理

    异常 (exception) 和错误 (error). 在 Objective-C 开发中,异常往往是由程序员的错误导致的 app 无法继续运行,比如我们向一个无法响应某个消息的NSObject 对象 ...

  6. Swift声明参考

    一条声明可以在你的程序里引入新的名字和构造.举例来说,你可以使用声明来引入函数和方法,变量和常量,或者来定义 新的命名好的枚举,结构,类和协议类型.你也可以使用一条声明来延长一个已经存在的命名好的类型 ...

  7. Swift 中范围和区间如何使用?

    虽然现在swift语言已经发展到了2.0版了,但是相信很多学习iOS开发的童鞋仍对swift语言存在各种各样的疑问,今天小编将为大家详细介绍swift中的范围和区间,下面我们一起来看看吧. Range ...

  8. iOS - Swift Swift 语言新特性

    1.Swift 2.0 带来哪些新变化 常规变化: 1.OS X 10.11.iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提高 Swift 的编程体验, ...

  9. go和swift

    你生命中的有些东西终究会失去,比如我住了6年的陈寨,这个聚集了郑州十几万IT民工的地方,说拆就拆了.再比如我玩了3年的坦克英雄,这个带给我太多快乐的游戏,说停就停了. 编程对我而言是种爱好,我上学6年 ...

随机推荐

  1. 解决Delphi7的自带的UTF-8编码转换函数BUG

    Delphi7及其以下版本的 VCL 只支持 Ansi, 所以... WideString 与 UTF8String (定义与 AnsiString 相同) 并没有办法正确的在 VCL 中显示 Del ...

  2. python全栈开发day40-浮动的四大特性,浮动带来的问题和解决问题,文本属性、字体属性和颜色介绍

    一.昨日内容总结 1.盒模型及其属性 2.文本级标签.行内块.块级标签 3.继承性.层叠性.权重 4.浮动四大特性 # 浮动元素脱离标准文档流 # 贴靠 # 字围效果 # 自动收缩或紧缩 二.今日内容 ...

  3. Linux 内核编译问题

    linux0.12 编译过程 https://www.bbsmax.com/A/GBJrMb0Kz0/ http://www.cnblogs.com/strugglesometimes/p/42313 ...

  4. ubuntu 18图形界面

    sh .start_mode.sh: 换操作方式(图形界面,终端界面): 桌面版: 界面中 ctrl + shift + t 打开终端 ctrl + shift + "+" 放大字 ...

  5. centos关机、重启、图形界面与命令行界面切换命令

    1.关机: init0;  poweroff;  halt;  shutdown 2.重启: init1;  reboot; 3.图形界面切换到命令行界面: init3; 或者,修改配置文件: #vi ...

  6. POJ 1222 熄灯问题【高斯消元】

    <题目链接> 题目大意: 有一个5*6的矩阵,每一位是0或者1. 没翻转一位,它的上下左右的数字也为改变.(0变成1,1变成0).要把矩阵中所有的数都变成0.求最少翻转次数的方案,输出矩阵 ...

  7. Dart语言特性必备了解!

    学习Dart语言,必须将以下的概念熟记于心: 在dart语言中,一切皆为对象.所有的对象都是一个类的实例.甚至整数.函数.null也看做是对象.所有的对象都继承于Object类 尽管Dart是强类型语 ...

  8. python 入门总结(一)

    自然语言用双引号,机器语言用单引号 例如dict的key 单行注释 # 多行注释 ''' ''' 输入print %s 字符串的占位符 %d 数字的占位符 如语句中有占位符那么所有的%都是占位符,可以 ...

  9. Logging模块 + traceback模块 + importlib模块 + requests模块

    Logiging模块日志级别 CRITICAL = 50FATAL = CRITICALERROR = 40WARNING = 30WARN = WARNINGINFO = 20DEBUG = 10N ...

  10. 8.10 正睿暑期集训营 Day7

    目录 2018.8.10 正睿暑期集训营 Day7 总结 A 花园(思路) B 归来(Tarjan 拓扑) C 机场(凸函数 点分治) 考试代码 A B C 2018.8.10 正睿暑期集训营 Day ...