「这是我参与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 的值;