在 Go 中編寫泛型函數時,接受具體類型也是有益的。然而,當嘗試使用這些特定類型的新實例初始化介面切片時,這會帶來挑戰。
一種方法可能看起來合乎邏輯:定義兩個類型參數,一種用於切片元素類型(X),另一種用於要實例化的具體類型(Y)。但是,當嘗試將 Y 的實例指派給 X 類型的元素時,此方法會失敗。
func Fill[X, Y any](slice []X){
for i := range slice {
slice[i] = new(Y) // not work!
}
}
出現此問題的原因是編譯器遺失了介面 X 及其實作 Y 之間的關係。 X 和 Y 都被視為不同的任何類型。
為了解決這個問題,可以在函數中採用明確轉換操作:
func Fill[X, Y any](slice []X) {
for i := range slice {
slice[i] = any(*new(Y)).(X)
}
}
但是,如果 Y 未實作 X,此方法會引發恐慌,這種情況會發生在嘗試將 *sync.Mutex(指標類型)指派給sync.Locker 等場景。
更強大且型別安全的解決方案涉及使用建構子:
func Fill[X any](slice []X, f func() X) {
for i := range slice {
slice[i] = f()
}
}
此函式接受傳回指定型別的新實例的建構子。這允許使用具體類型實例對切片進行簡潔、安全的初始化。
在具體型別打算用指標型別實例化的情況下,需要注意的是new(Y) 會導致零值。為了避免這種情況,可以調整建構子以傳回正確的指標值,例如 func() X { return &sync.Mutex{} }.
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3