「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。
- 本文主要介绍一些Swift中高阶函数的使用,本篇分析
Swift
提供的如下几个高阶函数:map
、flatMap
、compactMap
、filter
、reduce
。
1. map
Map 函数作用于 Collection
中的每一个元素,然后返回一个新的 Collection
。map函数获取一个闭包表达式成为它唯一的参数,之后数组中的每一个元素调用该闭包表达式,并返回该元素映射的值。
1.1 使用
- Int
数组转换
为String数组
我们可以直接对元素进行操作,也可以用$0
表示每一个元素。
- String数组转换为Int数组
可以发现返回的是一个可选值元素的数组,包含无法转换的nil。
- 生成一个
二维数组
生成一个新的Int数组,元素是多少元素就重复多少个
返回的是二维数组
1.2 源码分析
我们在collection.swift
查看map的实现
主要是先构造一个和原数组个数一样的数组,之后便利原数组中的每一个元素,通过transform
做相对应的操作,之后进行append
到新数组,最后返回一个新的数组
。
2. flatMap
2.1 使用
- flatMap使用
可以看到flatMap
是把数组中的数组进行了压平的操作,相当于二维数组转换为一维的数组
。
当然我们也可以对二维数组继续map
操作,转换为String
。
对于本身就是一维的话,map和flatmap
效果一样。
可以过滤
2.2 源码分析
可以发现和map类似,先创建一个数组里面的元素类型是SegmentOfResult.Element
。调用闭包的转换函数transform
,进行转换;之后通过append
添加每个数组的元素。
相比较我们的 map
来说, flatMap
最主要的两个作用一个是 压平
,一个是过滤空值
。
看个列子
可以看到这里我们使用map
做集合操作之后,得到的 reslut
是一个可选的可选,那么这里 其实我们在使用 result
的过程中考虑的情况就比较多
通过 flatMap
我们就可以得到一个可选值而不是可选的可选
看下源码:
flatMap
对于输入一个可选值时应用闭包返回一个可选值,之后这个结果会被压平, 也就是返回一个解包后的结果。本质上,相比 map
, flatMap
也就是在可选值层做了一个解包
。
使用 flatMap
就可以在链式调用时,不用做额外的解包工作
3. compactMap
当转换闭包返回可选值并且你期望得到的结果为非可选值的序列时,使用 compactMap
。
3.1 使用
或者
会自动过滤nil
3.2 源码分析
可以发现和之前的map类似的流程,从这里就可以得出结论,compactMap
与map
的区别就在于,map
将transform
后的结果直接放入result
中,而compactMap
使用if-let
后再放入result
中,而if-let
的作用就是解包和过滤nil
。
4. filter
filter是用来过滤的,类似我们oc中对数组使用谓词
4.1 使用
返回的是所有大于2的元素数组
4.2 源码分析
使用迭代器,遍历所有的元素,对于每个元素,调用闭包 isIncluded
,判断是否符合条件。符合后加入到我们创建的数组中。
5. reduce
主要是用来对集合中每个元素和叠加器做对应操作
@inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
@inlinable public func reduce<Result>(into initialResult: __owned Result, _ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows -> Result
复制代码
这2个方法有些类似的,差别在于闭包的定义。
-
第一个函数闭包,接收
Result
和Element
,返回闭包执行后的Result
,后续的操作是将每次闭包执行后的Result
当做下一个元素执行闭包的入参,遍历完所有元素; -
第二个函数闭包,接收的也是
Result
和Element
,没有返回值,并且Result
是用inout
修饰的,所以传入闭包的是Result
的地址,所以闭包的执行都是基于Result
进行操作的。
5.1 使用
- 找出数组中的最大值
- 把数组进行逆序
- 求和
5.2 源码分析
对于第一种:
累加器记录每次的状态,其次通过迭代器便利传入每次的结果和元素,遍历完成后,返回 accumulator
。
对于第二种:
和第一种的区别在于,没有每次便利的时候对accumulator赋值
,直接取它的地址&accumulator
遍历所有的元素,对于每个元素,调用闭包 updateAccumulatingResult
,参数是临时变量 accumulator 的地址
,闭包执行其实就是更新 accumulator
的值;