我正在嘗試使用泛型來創建一個引數化型別,它可以是:
T, *T, T[], map[interface{}]interface{}
其中:T是comparable型別,但不是介面。
我試圖通過受約束的排版來制定這一點,但由于MisplacedTypeParam編譯器錯誤而失敗:
type myType[T comparable] interface {
T | *T | T[] | map[interface{}]interface{}
}
我在使用時也遇到問題reflect,獲取介面的reflect.Kind
orreflect.Type將回傳介面底層的值的型別,這意味著我還沒有弄清楚如何斷言型別不是介面。
由此,我想知道表示這種型別的最佳替代方法是什么?
這是我正在進行的作業(https://github.com/mcwalrus/go-jitjson)及其主要部分:
type JitJSON[T any] struct {
data []byte
val *T
}
func (jit *JitJSON[T]) Unmarshal() (T, error) {
if jit.val != nil {
return *jit.val, nil
}
var val T
if jit.data == nil {
return val, nil
}
jit.val = &val
err := json.Unmarshal(jit.data, jit.val)
if err != nil {
return val, err
}
return *jit.val, nil
}
uj5u.com熱心網友回復:
不幸的是,您不能**簡單地將其實作為型別約束。因此,您必須依賴運行時檢查。
您可以通過 實作型別檢查reflect,但這在您的應用程式中可能是多余的,因為標準庫json在嘗試編組或解組不兼容的資料型別時已經產生了適當的錯誤。
如果您確實想使用reflect檢查引數化型別的確切型別,這是一種天真的但不正確的方法:
func f[T any]() {
var zero T
typ := reflect.TypeOf(zero)
fmt.Println(typ)
}
這適用于大多數型別,除了介面型別,它總是報告typ為<nil>. 這是因為介面值的分配在 Go 中是如何作業的。這是正確的方法:
func f[T any]() {
var zero T
typ := reflect.TypeOf(&zero).Elem()
fmt.Println(typ)
}
這是必要的,因為介面值在運行時只攜帶它們參考的具體型別的型別資訊。通過取介面變數的指標,取指標的型別,再取指標型別的元素,就可以提取出介面變數的實際型別。
** 我似乎無法找到一個簡明解釋為什么不能這樣做,但這里有一些困難:
comparable不能在型別聯合中使用- 型別約束不能組合
- 型別約束不能遞回定義
- 型別約束不能被否定
- 通常沒有與結構匹配的介面
uj5u.com熱心網友回復:
從 Go 1.19 開始,約束comparable已經只能通過嚴格可比的型別來實作,即==保證!=在運行時不會恐慌的型別。
所以這確實排除了介面。然而,它也排除了其他不嚴格可比但也不是介面的型別,例如[5]any或struct{ Data any }。
我不知道這對你來說是否足夠好。否則,無法根據減法定義約束型別集,即在集合表示法中,A \ B。從規范:
介面型別由介面元素串列指定。介面元素是方法或型別元素,其中型別元素是一個或多個型別術語的聯合。型別術語是單一型別或單一基礎型別。
如果您需要從計算中排除某些型別,您可能不得不回退到反射。還要考慮如果您的目標是解組 JSON,使用any約束并且*T可能是可以接受的(==檢查兩個指標??是否指向同一個變數)。畢竟,您應該將可尋址值傳遞給json.Unmarshal:
// code simplified for illustrative purposes
func (jit *JitJSON[T]) Unmarshal() (T, error) {
var val T
err := json.Unmarshal(jit.data, &val) // needs a pointer anyway
if err != nil {
return val, err
}
jit.val = &val
return *jit.val, nil
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/530639.html
標籤:去仿制药
