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
:
最後把咱們剛剛重載的方法刪掉,遷移完成了!!!
以爲文章還不錯的話能夠關注一下個人博客