Swift 模式匹配
前言
在 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")
}
- 对枚举做模式匹配时,如果
switch中case的值覆盖了枚举类型的所有情况时,不需要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 中为更多的基础语法引入了模式匹配,比如if和guard语句。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 模式匹配的更多相关文章
- Swift中switch强大的模式匹配
不少人觉得Swift中switch语句和C或C++,乃至ObjC中的差不多,此言大谬! 让本猫带领大家看一下Swift中switch语句模式匹配的威力. 所谓模式匹配就是利用一定模式(比如couple ...
- swift模式和模式匹配
模式和模式匹配 模式: 代表单个或者复合值得结构,也就是说模式不是一个特定的值,它是一种抽象的结构,[一句话,不是特指,是泛指].这样就可以用模式来匹配各种各样的值. 例如:(x,y)可以匹配元祖(1 ...
- swift 高级模式匹配 if case
let age = 22 let sex = "girl" if (sex == "girl" && age >= 18 &&am ...
- swift 的枚举、结构体、类
一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...
- swift错误和异常处理
异常 (exception) 和错误 (error). 在 Objective-C 开发中,异常往往是由程序员的错误导致的 app 无法继续运行,比如我们向一个无法响应某个消息的NSObject 对象 ...
- Swift声明参考
一条声明可以在你的程序里引入新的名字和构造.举例来说,你可以使用声明来引入函数和方法,变量和常量,或者来定义 新的命名好的枚举,结构,类和协议类型.你也可以使用一条声明来延长一个已经存在的命名好的类型 ...
- Swift 中范围和区间如何使用?
虽然现在swift语言已经发展到了2.0版了,但是相信很多学习iOS开发的童鞋仍对swift语言存在各种各样的疑问,今天小编将为大家详细介绍swift中的范围和区间,下面我们一起来看看吧. Range ...
- iOS - Swift Swift 语言新特性
1.Swift 2.0 带来哪些新变化 常规变化: 1.OS X 10.11.iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提高 Swift 的编程体验, ...
- go和swift
你生命中的有些东西终究会失去,比如我住了6年的陈寨,这个聚集了郑州十几万IT民工的地方,说拆就拆了.再比如我玩了3年的坦克英雄,这个带给我太多快乐的游戏,说停就停了. 编程对我而言是种爱好,我上学6年 ...
随机推荐
- java:冒泡排序、选择排序、插入排序实现
整数排序 给一组整数,按照升序排序,使用选择排序,冒泡排序,插入排序或者任何 O(n2) 的排序算法. 样例 样例 1: 输入: [3, 2, 1, 4, 5] 输出: [1, 2, 3, 4, 5] ...
- kubernetes 部署 traefik 以及kubernetes dashborad
前言 本来打算通过 traefik 来实现 kubernetes dashborad 的服务访问,可是在配置过程中始终报错.最后无奈只能通过nodeport来实现kubernetes dashbora ...
- 6-2 铁轨 uva 514
较为简单的stack题目 但是还是犯了一些错误: 1. 要想清空栈,直接重新定义较为方便! 2.在if(s.top()==x)时 加上 !s.empty() 否则程序会崩溃 3. 必须要加上i- ...
- java中与和或的注意点
1.&&和&的区别 &:无论左边是true是false.右边都运算. &&:当左边为false时,右边不运算. 2.|与||的区别 |:两边都参与运算. ...
- 分布式系统理论--CAP理论、BASE理论
问题的提出 在计算机科学领域,分布式一致性是一个相当重要且被广泛探索与论证问题,首先来看三种业务场景. 1.火车站售票 假如说我们的终端用户是一位经常坐火车的旅行家,通常他是去车站的售票处购买车票,然 ...
- HDU 2955_Robberies 小偷抢银行【01背包】
<题目链接> 题意: 先是给出几组数据,每组数据第一行是总被抓概率p(最后求得的总概率必须小于他,否则被抓),然后是想抢的银行数n.然后n行,每行分别是该银行能抢的钱数m[i]和被抓的概率 ...
- C# VideoAPI
using System; using System.Runtime.InteropServices; public class VideoAPI //视频API类 { // 视频API调用 [Dll ...
- 在webpack中使用postcss之插件cssnext
学习了precss插件包在webpack中的用法后,下面介绍postcss的另一个重要插件cssnext,步骤没有precss用法详细,主要介绍css4的语法,cssnext目前支持了部分新特性,你可 ...
- [CF521D]Shop
[CF521D]Shop 题目大意: 你有一个长度为\(k(k\le10^5)\)的数列\(A_{1\sim k}\),有\(n(n\le10^5)\)种操作,操作包含以下\(3\)种: 将\(A_x ...
- 2016年3月16日Android学习笔记
1.Jdk1.7以上switch语句中才能用字符串,在Android Studio中我改正了jdk的版本为1.8,但是还是出同样的错误,原来我用的sdk版本是4.4的,改成5的就没有问题了. 2.引入 ...