本小節講了一些關於泛型底層
的知識點和一些特殊狀況下
的使用。能夠當作擴充知識面去學習。git
func min<T: Comparable>(_ x: T, _ y: T) -> T {
returny<x?y:x
}
複製代碼
編譯器沒法爲這個函數直接生產代碼
,緣由以下:github
1.編譯器不知道T的```變量大小```
2.編譯器不知道須要調用的<函數是否有重載,因此也不知道須要調用的```函數的地址```
複製代碼
swift 爲函數引入了一套間接的中間層
來解決這個問題,引入了一個容器,編譯器會把泛型放到這個容器中 對於泛型的參數,編譯器還維護了一個或者多個目睹表(witness table)
,包括一個值目睹表
,以及每一個協議約束的協議目睹表
。 這些表將運行時的函數動態派發
到正確的實現中。 表裏實際上放的都是指針
。同時還記錄了類型大小和對齊方式
。swift
光看泛型特化這個詞很難理解它的用法和意思,後面咱們會講。app
使用泛型特化的緣由: 你們先了解一個swift的設計目標: "編譯一次,動態派發"
swift 泛型API只須要知道泛型函數或者類型的聲明,並不關心實現
。 因此結果的代碼不是那麼直接。這會致使運行時性能低
函數
swift庫中有不少泛型的使用,性能開銷很容易疊加。性能
這裏就引入了泛型特化(generic specialization)
來避免這個沒必要要的開銷。 泛型特化的本質: 編譯器按照具體的參數類型
將函數進行複製
。 文章一開始的例子中,可能針對於Int的參數類型特化出一個方法是這樣的學習
func min(_ x: Int, _ y: Int) -> Int {
returny<x?y:x
}
複製代碼
泛型特化不只能去掉虛擬派發的開銷
, 還可讓內聯
等進一步優化成爲可能優化
泛型特化的決定在編譯時
進行。特化的參數類型極可能是你常常使用
的具體類型, 若是你常常使用Int 只用過一次float 那麼就會特化出上面的函數。spa
缺點:泛型定義和調用在同一個文件中
時,泛型特化才能工做,只能在模塊內使用😅(標準庫中的泛型方法除外,由於標準庫的定義對於全部模塊都是可見的)設計
由於泛型特化是一個很嚴重的限制,因此編譯器引入了一個標誌來啓用全模塊優化
能夠經過向 swiftc 傳遞 -whole-module-optimization 來開啓全模塊優化
通常都是在發佈版本中
進行這項操做,
優勢:
大幅度提高性能 缺點:
會帶來更長的編譯時間
@_specialize 是一個非官方
的標籤,計劃未來會引入到標準庫中。 做用:將你的泛型代碼進行指定版本的特化,使其在其餘模塊中
也可用。(你必需要指明想要進行特化的類型列表) 使用以下:
@_specialize(exported: true, where T == Int)
@_specialize(exported: true, where T == String)
public func min<T: Comparable>(_ x: T, _ y: T) -> T {
returny<x?y:x
}
複製代碼
over~