泛型語法改進第一彈 —— Opaque Result Types

SE-0244 Opaque Result Types 提案前一段時間經過了 review 而且在 Swift 5.1 裏完成了實現,我最先閱讀這份提案的時候理解不是很透徹,今天比較仔細地讀了這篇 Improving the UI of generics 以後有了更多的認識,並且發現本身以前發的 tweet 裏有一些錯誤的認知,因此這裏寫篇文章,但願用最直白的方式解釋清楚提案的內容,跟你們分享一下我本身的理解。git

Opaque Result Types?

用最最簡單的一句話來介紹這個提案的內容,就是它能讓被調用者選擇泛型返回值的具體類型。github

這是什麼意思呢?讓咱們來看目前最多見的泛型函數聲明:swift

protocol Shape { ... }

func generic<T: Shape>() -> T { ... }

let x: Rectangle = generic() // type(of: x) == Rectangle, 調用方決定返回值類型
複製代碼

這很好,但有時候咱們不但願暴露出具體的返回類型,也不想讓調用者去依賴具體的類型,以前咱們能夠直接使用泛型類型:app

func generic() -> Shape { ... }

let x = generic() // type(of: x) == Shape
複製代碼

雖然這樣確實能達成咱們的目的,但也會帶來一些反作用,例如說性能問題,由於實際上 generic 返回的是一個實例的容器。dom

咱們更但願的是可以像第一種聲明那樣,在編譯時就肯定返回值的具體類型,而且由被調用方去決定:函數

func reverseGeneric() -> some Shape { return Rectangle(...)  }

let x = reverseGeneric() 
// type(of: x) == Rectangle
// 而且 x 的類型根據 reverseGeneric 的具體實現決定
複製代碼

經過引入 some 這個關鍵字去修飾返回值,就可讓被調用方選擇具體的返回值類型,而且是在編譯時肯定下來的,這意味着咱們不須要額外的容器去存放返回的實際值。性能

另外它還能夠做爲屬性使用:ui

func someNumber() -> some Numeric { ... }

var number: some Numeric = someNumber()
複製代碼

它能夠?

在這裏咱們須要先確立一個條件,經過 some 修飾的類型,都會在編譯時肯定下來,能夠簡單地理解爲被調用方負責傳入的一個泛型參數,相關的功能和限制都是基於這個特性延伸出來的。spa

根據前面的條件,若是返回值使用了 some 修飾,編譯器能夠推導出兩件很重要的事情:3d

  1. 同一個函數簽名,返回值的類型確定也只能是同一個具體類型
  2. 外部不可以依賴函數實現裏使用的返回值具體類型

這意味着什麼?在以前,兩個遵循了 Equatable 的實例不能判斷是否相等,由於咱們並不知道它們具體的類型是否同樣,但若是使用了 some,而且是由同一個函數返回的,那就徹底不是問題了:

func randomNumber() -> some Equatable {
    let i: Int = 32
    return i
}

let x = randomNumber()
let y = randomNumber()

// 在這裏使用 == 是沒問題的
// 由於 x 跟 y 都是由 randomNumber 返回的
// 因此它們的具體類型必然一致
print(x == y)
複製代碼

可是控制返回值類型的是調用方,因此你不可以依賴調用方的具體實現:

func randomNumber() -> some Equatable {
    let i: Int = 32
    return i
}

var otherNumber: Int = 38
var x = randomNumber()
x = otherNumber // error
複製代碼

雖然你知道 randomEquatableNumber 的實現裏使用的是 Int,但具體的實現有可能隨時被調整,因此你不能依賴它。

結語

在這裏只是簡單地介紹了一些比較核心的內容,想了解更多細節的朋友能夠看提案。實際上這個提案只是整個泛型語法改進計劃裏的第一步,以後等我有了更加深刻的瞭解再作更多分享。

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

相關文章
相關標籤/搜索