近期一篇主題為的文章引起了廣泛討論。因為 Go 開發者對「泛型」這項特性期盼已久,但最後卻發現有所落差。
Go 泛型主要設計者 Ian Lance Taylor 也留意到了相關的討論,於是近日他在 Go 官方部落格了自己 2021 年的演講——《》,來介紹使用 Go 泛型的最佳時機。
上文提到的文章指出,從歷史上看,C++、D 乃至 Rust 等系統語言一直採用單態化方法實現泛型。然而,Go 1.18 的泛型實現並不完全依靠單態化 (Monomorphization),而是採用了一種被稱為"GCShape stenciling with Dictionaries"的部分單態化技術。這種方法的好處是可以大幅減少程式碼量,但在特定情況下,會導致程式碼速度變慢。
Ian Lance Taylor 表示,Go 的通用開發準則有要求:開發者應通過編寫程式碼而不是定義型別來編寫 Go 程式。當涉及到泛型時,如果通過定義型別引數約束來編寫程式,那一開始就走錯了路。正解應該是從編寫函數開始,當明確了型別引數的作用後,再新增型別引數就很容易了。
接著,Ian 列舉了 4 種型別引數能有效發揮作用的情況:
- 使用語言定義的特殊容器型別
- 通用資料結構
- 型別引數首選是函數,而非方法的情況
- 不同型別需要實現通用方法
同時也提醒了不適合使用型別引數的情況:
- 不要使用型別引數替換介面型別 (Interface Type)
- 如果方法實現不同,不要使用型別引數
- 在適當的地方使用反射 (reflection)
最後,Ian 給出了簡要的泛型使用方針,當開發者發現自己多次編寫完全相同的程式碼,而這些副本之間的唯一區別僅在於使用了不同型別,這時候便可以考慮使用型別引數。換句話說,即開發者應避免使用型別引數,直到發現自己要多次編寫完全相同的程式碼。
延伸閱讀: