Swift进阶-24-Swift中高阶函数的使用

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。

  • 本文主要介绍一些Swift中高阶函数的使用,本篇分析 Swift 提供的如下几个高阶函数:mapflatMapcompactMapfilterreduce

1. map

Map 函数作用于 Collection 中的每一个元素,然后返回一个新的 Collection 。map函数获取一个闭包表达式成为它唯一的参数,之后数组中的每一个元素调用该闭包表达式,并返回该元素映射的值。

1.1 使用

  • Int数组转换为String数组

image.png

我们可以直接对元素进行操作,也可以用$0表示每一个元素。

  • String数组转换为Int数组

image.png

可以发现返回的是一个可选值元素的数组,包含无法转换的nil。

  • 生成一个二维数组

生成一个新的Int数组,元素是多少元素就重复多少个

image.png

返回的是二维数组

1.2 源码分析

我们在collection.swift 查看map的实现
image.png

主要是先构造一个和原数组个数一样的数组,之后便利原数组中的每一个元素,通过transform做相对应的操作,之后进行append 到新数组,最后返回一个新的数组

2. flatMap

2.1 使用

  • flatMap使用

image.png

可以看到flatMap是把数组中的数组进行了压平的操作,相当于二维数组转换为一维的数组

image.png

当然我们也可以对二维数组继续map操作,转换为String

image.png

对于本身就是一维的话,map和flatmap效果一样。

image.png

可以过滤

2.2 源码分析

image.png

可以发现和map类似,先创建一个数组里面的元素类型是SegmentOfResult.Element。调用闭包的转换函数transform,进行转换;之后通过append 添加每个数组的元素。
相比较我们的 map 来说, flatMap 最主要的两个作用一个是 压平,一个是过滤空值

看个列子

image.png
可以看到这里我们使用map做集合操作之后,得到的 reslut 是一个可选的可选,那么这里 其实我们在使用 result 的过程中考虑的情况就比较多

image.png
通过 flatMap 我们就可以得到一个可选值而不是可选的可选

看下源码:

image.png

flatMap 对于输入一个可选值时应用闭包返回一个可选值,之后这个结果会被压平, 也就是返回一个解包后的结果。本质上,相比 map , flatMap 也就是在可选值层做了一个解包

image.png

使用 flatMap 就可以在链式调用时,不用做额外的解包工作

image.png

3. compactMap

当转换闭包返回可选值并且你期望得到的结果为非可选值的序列时,使用 compactMap

3.1 使用

image.png

或者
image.png

自动过滤nil

3.2 源码分析

image.png

可以发现和之前的map类似的流程,从这里就可以得出结论,compactMapmap的区别就在于,maptransform后的结果直接放入result中,而compactMap使用if-let后再放入result中,而if-let的作用就是解包和过滤nil

4. filter

filter是用来过滤的,类似我们oc中对数组使用谓词

4.1 使用

image.png

返回的是所有大于2的元素数组

4.2 源码分析

image.png

使用迭代器,遍历所有的元素,对于每个元素,调用闭包 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个方法有些类似的,差别在于闭包的定义。

  • 第一个函数闭包,接收ResultElement,返回闭包执行后的Result,后续的操作是将每次闭包执行后的Result当做下一个元素执行闭包的入参,遍历完所有元素;

  • 第二个函数闭包,接收的也是ResultElement,没有返回值,并且Result是用inout修饰的,所以传入闭包的是Result的地址,所以闭包的执行都是基于Result进行操作的。

5.1 使用

  • 找出数组中的最大值

image.png

  • 把数组进行逆序

image.png

  • 求和

image.png

5.2 源码分析

对于第一种:

image.png

累加器记录每次的状态,其次通过迭代器便利传入每次的结果和元素,遍历完成后,返回 accumulator

对于第二种:

image.png

和第一种的区别在于,没有每次便利的时候对accumulator赋值,直接取它的地址&accumulator
遍历所有的元素,对于每个元素,调用闭包 updateAccumulatingResult,参数是临时变量 accumulator 的地址,闭包执行其实就是更新 accumulator 的值;

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享