Swift 4.1:苹果为何将FlatMap重命名为compactMap

哈Ha!

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



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



对于多个版本,Swift具有mapflatMap 。 但是,在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 } // [1, 2, 3, 4, 5, 6, 7, 8, 9] 

这是flatMap方法应如何工作的一个很好的例子。 我们将转换(映射)源列表的每个元素并创建一个新序列。 多亏了flatMap最终结果是转换序列的扁平化结构。

Optional.flatMap <U>(_:(Wrapped)-> U?)-> U?


第二个重载是针对可选类型的。 如果要调用的可选类型具有值,则将使用不带可选包装器(未包装的值)的值来调用闭包,并且您可以返回转换后的可选值。

 let a: Int? = 2 let transformedA = a.flatMap { $0 * 2 } // 4 let b: Int? = nil let transformedB = b.flatMap { $0 * 2 } // nil 

Sequence.flatMap <U>(_:(元素)-> U?)-> [U]


第三次重载将帮助您了解compactMap 。 该版本与第一个版本相同,但有一个重要区别。 在这种情况下,闭包返回可选的。 flatMap处理,跳过返回的nil值,并将其余所有值包括在结果中,作为没有包装器的值。

 let array = [1, 2, 3, 4, nil, 5, 6, nil, 7] let arrayWithoutNils = array.flatMap { $0 } // [1, 2, 3, 4, 5, 6, 7] 

但是在这种情况下,不执行排序。 因此,此版本的flatMapflatMap的纯功能定义更接近于map 。 而且此重载的问题在于,您可能无法在map可以正常工作的地方正确使用它。

 let array = [1, 2, 3, 4, 5, 6] let transformed = array.flatMap { $0 } // same as array.map { $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

Source: https://habr.com/ru/post/zh-CN414809/


All Articles