哈Ha!
我叫Alexander Zimin,我是Badoo的iOS开发人员。 这是我的同事Schwib撰写的一篇文章的译文,他在其中描述了Swift中的flatMap函数是什么样的,以及为什么其中的重载之一被重命名为compactMap。 本文对于理解
Swift仓库中发生的过程
及其演变以及一般开发都非常有用。

在函数式编程中,对
flatMap
函数
flatMap
什么有明确的定义。
flatMap
方法采用一个列表和一个转换函数(对于每个转换,其期望获得零个或多个值),将其应用于列表的每个元素,并创建一个(扁平化的)列表。 此行为不同于简单
map
函数,后者将变换应用于每个值,并且期望每个变换仅获得一个值。

对于多个版本,Swift具有
map
和
flatMap
。 但是,在
Swift 4.1中,您不能再将
flatMap
应用于一系列值,而仍然传递一个返回可选值的闭包。 现在有一个
compactMap
方法。
首先,了解创新的本质可能并不容易。 如果
flatMap
运作良好,为什么要引入单独的方法? 让我们弄清楚。
版本4.1之前的Swift标准库为
flatMap
提供了三种重载实现:
1. Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element], S : Sequence 2. Optional.flatMap<U>(_: (Wrapped) -> U?) -> U? 3. Sequence.flatMap<U>(_: (Element) -> U?) -> [U]
让我们浏览所有三个选项,看看它们的作用。
Sequence.flatMap <S>(_:(元素)-> S)-> [S.Element],其中S:序列
第一个重载用于序列,其中闭包采用该序列的一个元素并转换为另一个序列。
flatMap
所有这些转换后的序列
flatMap
为作为结果返回的最终序列。 例如:
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let flattened = array.flatMap { $0 }
这是
flatMap
方法应如何工作的一个很好的例子。 我们将转换(映射)源列表的每个元素并创建一个新序列。 多亏了
flatMap
最终结果是转换序列的扁平化结构。
Optional.flatMap <U>(_:(Wrapped)-> U?)-> U?
第二个重载是针对可选类型的。 如果要调用的可选类型具有值,则将使用不带可选包装器(未包装的值)的值来调用闭包,并且您可以返回转换后的可选值。
let a: Int? = 2 let transformedA = a.flatMap { $0 * 2 }
Sequence.flatMap <U>(_:(元素)-> U?)-> [U]
第三次重载将帮助您了解
compactMap
。 该版本与第一个版本相同,但有一个重要区别。 在这种情况下,闭包返回可选的。
flatMap
处理,跳过返回的nil值,并将其余所有值包括在结果中,作为没有包装器的值。
let array = [1, 2, 3, 4, nil, 5, 6, nil, 7] let arrayWithoutNils = array.flatMap { $0 }
但是在这种情况下,不执行排序。 因此,此版本的
flatMap
比
flatMap
的纯功能定义更接近于
map
。 而且此重载的问题在于,您可能无法在
map
可以正常工作的地方正确使用它。
let array = [1, 2, 3, 4, 5, 6] let transformed = array.flatMap { $0 }
flatMap
这种用法对应于第三个重载,将转换后的值隐式包装在可选变量中,然后删除包装器以添加到结果中。 如果未正确使用字符串转换,这种情况将变得特别有趣。
struct Person { let name: String } let people = [Person(name: “Foo”), Person(name: “Bar”)] let names = array.flatMap { $0.name }
在4.0版之前的Swift中,我们将转换为
[“Foo”, “Bar”]
。 但是从版本4.0开始,字符串值实现了Collection协议。 因此,在这种情况下,我们使用
flatMap
而不是第三个重载,将与第一个重载相对应,并且我们将从转换后的值中获得“扁平化”结果:
[“F”, “o”, “o”, “B”, “a”, “r”]
调用
flatMap
不会出现错误,因为允许使用。 但是逻辑将被破坏,因为结果的类型为
Array<Character>.Type
,而不是预期的
Array<String>.Type
。
结论
为了避免滥用
flatMap
,已从新的Swift版本中删除了第三个重载版本。 为了解决相同的问题(删除nil-values),现在您需要使用单独的方法
compactMap
。