似乎已弃用 Swift 4.1 flatMap
。但是 Swift 4.1 compactMap
中有一种新方法可以做同样的事情吗?
使用flatMap
,您可以转换集合中的每个对象,然后删除任何nil项。
与flatMap一样
let array = ["1", "2", nil]
array.flatMap { $0 } // will return "1", "2"
与compactMap一样
let array = ["1", "2", nil]
array.compactMap { $0 } // will return "1", "2"
compactMap
正在做同样的事情。
这两种方法有什么区别?为什么Apple决定重命名该方法?
答案 0 :(得分:18)
flatMap
有三种不同的变体。接受返回Optional值的闭包的Sequence.flatMap(_:)
变体已被弃用。 Sequence和Optional上的flatMap(_:)
的其他变体保持不变。提案文件中解释的原因是由于滥用。
在新方法flatMap
下,不推荐的compactMap
变体功能完全相同。
详见here。
答案 1 :(得分:18)
Swift标准库为flatMap
函数定义了3个重载:
Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element]
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]
可以通过两种方式滥用最后一个重载函数:
考虑以下结构和数组:
struct Person {
var age: Int
var name: String
}
let people = [Person(age: 21, name: "Osame"), Person(age: 17, name: "Masoud"), Person(age: 20, name: "Mehdi")]
第一种方法:附加包装和展开:
如果您需要获取people
数组中包含的人员年龄的数组,则可以使用以下两个函数:
let flatMappedAges = people.flatMap({$0.age}) // prints: [21, 17, 20]
let mappedAges = people.map({$0.age}) // prints: [21, 17, 20]
在这种情况下,map
函数将完成此任务,并且无需使用flatMap
,因为两者都会产生相同的结果。此外,在flatMap用例内部有一个无用的包装和解包过程。(Closure参数用Optional包装其返回的值,flatMap的实现在返回Optional之前将其解包装)
第二种方式-符合收集协议的字符串:
认为您需要从people
数组中获取人员姓名列表。您可以使用以下行:
let names = people.flatMap({$0.name})
如果您使用的是4.0之前的快速版本,则将获得
的转换列表。["Osame", "Masoud", "Mehdi"]
,但在较新的版本中,String
符合Collection
协议,因此,您对flatMap()
的使用将匹配第一个重载函数,而不是第三个重载函数,从而使您转换后的值:
["O", "s", "a", "m", "e", "M", "a", "s", "o", "u", "d", "M", "e", "h", "d", "i"]
结论:他们不推荐flatMap()的第三次重载
由于存在这些误用,Swift团队决定将第三个重载弃用到flatMap函数。对于到目前为止您需要处理Optional
的情况,他们的解决方案是引入一个名为compactMap()
的新函数,它将为您带来预期的结果。