Swift 4.1 遷移小技巧 —— CompactMap

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-0187swift

最初這個提案用了 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 進行重載,例如繼承自 SequenceCollection

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

最後把咱們剛剛重載的方法刪掉,遷移完成了!!!

以爲文章還不錯的話能夠關注一下個人博客

相關文章
相關標籤/搜索