Swift 4.1 中引入了一个“新”函数 compactMap
,在这里给你们介绍一个迁移的小技巧。html
compactMap
的由来在开始以前,先简单介绍一下 compactMap
的由来,咱们都知道以前 flatMap
有两个重载版本,第一个是用来 flat 集合的:git
let arr = [[1, 2, 3], [4, 5]]
let newArr = arr.flatMap { $0 }
// newArr 的值为 [1, 2, 3, 4, 5]
复制代码
第二个是用来 flat 可选值的:github
let arr = [1, 2, 3, nil, nil, 4, 5]
let newArr = arr.flatMap { $0 }
// newArr 的值为 [1, 2, 3, 4, 5]
复制代码
这两个版本虽然都是用来降维的,但第二个版本除了 flat 以外其实还有 filter 的做用,在使用时容易产生歧义,因此社区认为最好把第二个版本从新拆分出来,使用一个新的方法命名,就产生了这个提案 SE-0187。swift
最初这个提案用了 filterMap
这个名字,但后来通过讨论,就决定参考了 Ruby 的 Array::compact
方法,使用 compactMap
这个名字。app
虽然就 API 层面来讲,这只是单纯的名字修改,但全局替换很难实现,而逐个编译警告处理又太过麻烦,在这里我想介绍一个更加便捷的迁移方法:构造一个 flatMap
来重载标准库的实现,而后再借助 Xcode 的重构工具对函数进行重命名。ide
方式很直白,惟一的问题在于如何重载,首先看一下 flatMap
的声明,flatMap
是声明在 Sequence
类型里的:函数
// stdlib/public/core/SequenceAlgorithms.swift
extension Sequence {
@inline(__always)
@available(swift, deprecated: 4.1, renamed: "compactMap(_:)",
message: "Please use compactMap(_:) for the case where closure returns an optional value")
public func flatMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
return try _compactMap(transform)
}
}
复制代码
再参考我以前的博文【译】Swift 泛型宣言:工具
...ui
参考 Swift 官方文档 Protocols 小节里的最后一段:spa
“If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.”
约束越多的 conformance 优先级越高
...
综上可得,因为 flatMap
是一个声明在 Sequence
里的泛型函数,因此咱们能够在一个约束更多的 extension 里声明一个 flatMap
进行重载,例如继承自 Sequence
的 Collection
:
protocol Collection: Sequence {}
复制代码
又或者是某个 Nested Type,例如 Array
,鉴于咱们项目里基本上都是使用 Array.flatMap
,因此直接重载便可:
extension Array {
func flatMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
return try compactMap(transform)
}
}
复制代码
接着右键 -> Refactor -> Rename,把 flatMap
改为 compactMap
:
最后把咱们刚刚重载的方法删掉,迁移完成了!!!
以为文章还不错的话能够关注一下个人博客