「这是我参与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个方法有些类似的,差别在于闭包的定义。

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

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

    5.1 使用

  • 找出数组中的最大值
  • 把数组进行逆序
  • 5.2 源码分析

    对于第一种:

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

    对于第二种:

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

  • 分类:
    iOS
    标签: