深入讲解Swift中的模式匹配

 更新时间:2020年6月30日 23:37  点击:1775

模式匹配

模式匹配是 Swift 中非常常见的一种编程模式,使用模式匹配,可以帮助我们写出简明、清晰以及易读的代码,使我们的代码变得简洁而强大。

条件判断中的模式匹配

条件判断是我们使用最普遍的流程控制,在 Swift 中,只能接受 Bool 类型的值作为条件体;除了直接判断 Bool 值之外,我们还能使用使用条件语句进行可选绑定,这在我们开发中是非常常用的方式。

匹配枚举值

在 Swift 中,创建的枚举类型默认是不可比较的(没有实现Comparable协议),这就意味着我们不能直接使用==操作符来判断两个枚举值是否相等,这种情况下,需要使用模式匹配:

创建一个枚举类型:

enum Result {
 case success
 case failure
}

初始化一个枚举值:

let result = Result.success

使用模式匹配来判断创建的枚举值的值:

if case .success = result {
 print("Value of result is success.")
}

可选绑定

创建一个可选值:

let optionalInt: Int? = 1

使用可选绑定的方式进行解包:

if let val = optionalInt {
 print("The value of optionalInt is (val)")
}
func handleGuard() {
 guard let val = optionalInt else {
 return
 }
 print("The value of optionalInt is (val)")
}
handleGuard()

可选绑定的另外一种模式,这也是可选绑定中最基础的模式:

if case .some(let val) = optionalInt {
 print("The value of optionalInt is (val)")
}

还可以简化为:

if case let val? = optionalInt {
 print("The value of optionalInt is (val)")
}

循环中的模式匹配

问题来了,if let 模式的可选绑定,只能实现一个可选值的绑定,如果我们需要匹配一个数组里边的可选值怎么办呢?这时候我们就不能使用 if let 的形式了,需要使用到 if case let 的形式

创建一个包含可选值的数组:

let values: [Int?] = [1, nil, 3, nil, 5, nil, 7, nil, 9, nil]

进行遍历:

for val in values {
 print("Value in values is (String(describing: val))")
}

或者:

var valuesIterator = values.makeIterator()
while let val = valuesIterator.next() {
 print("Value in values is (String(describing: val))")
}

我们得到了所有的值与可选值,如果我们需要过滤可选值,我们可以这样做:

for val in values.compactMap({ $0 }) {
 print("Value in values is (val)")
}

这样做,增加了时间复杂度,需要进行两次遍历才能将数据过滤出来。我们可以使用模式匹配的方式来这样做:

for case let val? in values {
 print("Value in values is (val)")
}

或者:

valuesIterator = values.makeIterator()
while let val = valuesIterator.next(), val != nil {
 print("Value in values is (String(describing: val))")
}

这样就可以将 nil 值给过滤了,是不是很简单?还可以使用 for case 匹配枚举值数组:

let results: [Result] = [.success, .failure]
for case .success in results {
 print("Values in results contains success.")
 break
}

对于复杂的枚举类型:

enum NetResource {
 case http(resource: String)
 case ftp(resource: String)
}

let nets: [NetResource] = [.http(resource: "https://www.baidu.com"), .http(resource: "https://www.apple.cn"), .ftp(resource: ftp://192.0.0.1)]

过滤 http 的值:

for case .http(let resource) in nets {
 print("HTTP resource (resource)")
}

for 循环使用 where 从句

除此之外,我们还可以在 for 循环后边跟上一个 where 从句来进行模式匹配:

for notNilValue in values where notNilValue != nil {
 print("Not nil value: (String(describing: notNilValue!))")
}

查询一个数组里边所有能被3整除的数:

let rangeValues = Array(0...999)
for threeDivideValue in rangeValues where threeDivideValue % 3 == 0 {
 print("Three devide value: (threeDivideValue)")
}

查询所有含有3的数:

for containsThree in rangeValues where String(containsThree).contains("3") {
 print("Value contains three: (containsThree)")
}

Switch 中的模式匹配

Switch 中的模式匹配也很常用,在 Switch 中合理地使用模式匹配可以为我们带来很多好处,可以使我们的代码更简洁,同时可以减少代码量和增加开发效率。

区间匹配

let value = 188

switch value {
case 0..<50:
 print("The value is in range [0, 50)")
case 50..<100:
 print("The value is in range [50, 100)")
case 100..<150:
 print("The value is in range [100, 150)")
case 150..<200:
 print("The value is in range [150, 200)")
case 200...:
 print("The value is in range [200, ")
default: break
}

// The value is in range [150, 200)

匹配元组类型

创建一个元组类型:

let tuples: (Int, String) = (httpCode: 404, status: "Not Found.")

进行匹配:

switch tuples {
case (400..., let status):
 print("The http code is 40x, http status is (status)")
default: break
}

创建一个点:

let somePoint = (1, 1)

进行匹配:

switch somePoint {
case (0, 0):
 print("(somePoint) is at the origin")
case (_, 0):
 print("(somePoint) is on the x-axis")
case (0, _):
 print("(somePoint) is on the y-axis")
case (-2...2, -2...2):
 print("(somePoint) is inside the box")
default:
 print("(somePoint) is outside of the box")
}

如上,我们在匹配的时候可以使用下划线 _ 对值进行忽略:

switch tuples {
case (404, _):
 print("The http code is 404 not found.")
default: break
}

在 switch case 中使用 where 从句

在 case 中使用 where 从句可以使我们的模式匹配看起来更加精简,使匹配的模式更加紧凑:

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
 print("((x), (y)) is on the line x == y")
case let (x, y) where x == -y:
 print("((x), (y)) is on the line x == -y")
case let (x, y):
 print("((x), (y)) is just some arbitrary point")
}

总结

Swift 中模式匹配的种类

模式匹配可以说是 Swift 中非常强大的一种编程模式,使用良好的模式匹配,可以帮助我们写出简介、优雅的代码,Swift 中的模式匹配包括以下种类:

  • 条件判断:if, guard
  • 可选绑定:if let, guard let, while let ...
  • 循环体:for, while, repeat while
  • switch
  • do catch

什么时候使用 where 从句?

我们可以在前文的例子中看到,在很多进行模式匹配的地方还使用了 where 从句,where 从句的作用就相当于在模式匹配的基础上在加上条件限制,使用 where 从句等价于:

for notNilValue in values {
 if notNilValue != nil {
  print("Not nil value: (String(describing: notNilValue!))")
 }
}

可以看出,使用 where 从句可以使我们的代码更加简洁和易读,什么时候使用 where ? 或者说在哪里可以使用 where ? Swift 文档中并没有对 where 的详细使用进行介绍,但是在实践中发现,where 可以使用在以下地方:

  • for 循环语句
  • switch 分支

而对于 if, guard 与 while ,我们不能在其后面添加 where 从句,因为他们本身可以进行多个条件的组合. where 从句还有一个用法就是对泛型类型进行类型约束,这在泛型的章节中会有介绍.

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对猪先飞的支持。

[!--infotagslink--]

相关文章

  • swift中利用runtime交换方法的实现示例

    这篇文章主要给大家介绍了关于swift中利用runtime交换方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。...2020-06-30
  • Swift设置UILabel内边距的实例代码

    有时候,我们需要一个显示文字,又想这些文字与边界之间有自定义的边距,所以下面这篇文章主要给大家介绍了关于Swift设置UILabel内边距的相关资料,需要的朋友可以参考下...2021-10-14
  • swift中的@UIApplicationMain示例详解

    这篇文章主要给大家介绍了关于swift中@UIApplicationMain的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。...2020-06-30
  • Swift实现多个TableView侧滑与切换效果

    这篇文章主要为大家详细介绍了Swift实现多个TableView侧滑与切换效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-30
  • 详解swift中xcworkspace多项目管理

    给大家详细讲解了IOS开发中swift语言xcworkspace多项目管理的方法和介绍,一起参考一下。...2020-06-30
  • Swift 中如何使用 Option Pattern 改善可选项的 API 设计

    这篇文章主要介绍了Swift 中如何使用 Option Pattern 改善可选项的 API 设计,帮助大家更好的进行ios开发,感兴趣的朋友可以了解下...2020-10-23
  • 如何使用Swift来实现一个命令行工具的方法

    这篇文章主要介绍了如何使用Swift来实现一个命令行工具,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • Swift中的命名空间详解

    这篇文章主要给大家介绍了关于Swift中命名空间的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • 浅析Swift中struct与class的区别(汇编角度底层分析)

    这篇文章主要介绍了Swift中struct与class的区别 ,本文从汇编角度分析struct与class的区别,通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-30
  • Swift缩放并填充图片功能的实现

    最近有一个需求,就是将图片先等比例缩放到指定大小,然后将空余出来空间填充为黑色,返回指定大小的图片。本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧...2021-11-02
  • OpenResty中正则模式匹配的2种方法详解

    在 OpenResty 中,同时存在两套正则表达式规范:Lua 语言的规范和 Nginx 的规范,下面这篇文章主要给大家介绍了关于OpenResty中正则模式匹配的2种方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。...2020-06-30
  • Swift中优雅处理闭包导致的循环引用详解

    这篇文章主要给大家介绍了关于Swift中优雅的处理闭包导致的循环引用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Swift具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-30
  • Swift实现倒计时5秒功能

    这篇文章主要为大家详细介绍了Swift实现倒计时5秒功能,在“登录”和“注册”页面也有相似功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-30
  • Swift 使用 Observe 监测页面滚动的实现方法

    这篇文章主要介绍了Swift 使用 Observe 监测页面滚动的实现方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-30
  • Swift在控件中添加点击手势的方法

    这篇文章主要介绍了Swift在控件中添加点击手势的方法,本文讲解如何在tableview的headerview中添加点击手势的方法,需要的朋友可以参考下...2020-06-30
  • Swift如何使用类型擦除及自定义详解

    有很多地方会用到类型擦除,并且它们的作用的各不相同。下面这篇文章主要给大家介绍了关于Swift如何使用类型擦除及自定义的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2020-06-30
  • Swift利用CoreData如何存储多种数据类的通讯录

    这篇文章主要给大家介绍了关于Swift利用CoreData如何存储多种数据类的通讯录的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。...2020-06-30
  • SwiftUI 中创建反弹动画的实现

    这篇文章主要介绍了SwiftUI 中创建反弹动画的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-30
  • Swift中动态调用实例方法介绍

    这篇文章主要介绍了Swift中动态调用实例方法介绍,在Swift中有一类很有意思的写法,可以让我们不直接使用实例来调用这个实例上的方法,而是通过类型取出这个类型的某个实例方法的签名,然后再通过传递实例来拿到实际需要调用的方法,需要的朋友可以参考下...2020-06-30
  • iOS Swift UICollectionView横向分页滚动,cell左右排版问题详解

    UICollectionView是iOS中比较常见的一个控件,这篇文章主要给大家介绍了关于iOS Swift UICollectionView横向分页滚动,cell左右排版问题的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随小编来一起学习学习吧。...2020-06-30