我正在嘗試在 Golang 中實作一些快取函式,但我希望它們對字串和實作Stringer介面的其他物件都有效。我正在嘗試使用 Golang 泛型,這就是我目前所擁有的:
import (
"fmt"
)
type String interface {
~string | fmt.Stringer
}
但是,這會產生錯誤cannot use fmt.Stringer in union (fmt.Stringer contains methods)。有沒有辦法在不依賴反射或型別裝箱/拆箱的情況下做到這一點?
uj5u.com熱心網友回復:
這種混淆可能是有道理的,因為型別引數提案建議使用類似 yours 的代碼,但最終成為 Go 1.18 中的實作限制。
它在規范和 Go 1.18 發行說明中提到。規格是規范性參考:
實作限制:一個聯合(有多個術語)不能包含預先宣告的識別符號
comparable或指定方法的介面,或嵌入comparable或指定方法的介面。
對于為什么 Go 1.18 版本中沒有包含它,還有一個有點廣泛的解釋。tl;dr 正在簡化聯合型別集的計算(盡管在 Go 1.18 中,型別引數的方法集也沒有隱式計算......)。
T還要考慮一下,不管有沒有這個限制,除了傳遞給使用反射的函式之外,您可能不會獲得任何有用的東西。要呼叫方法,~string | fmt.Stringer您仍然需要型別斷言或型別切換。
請注意,如果此類約束的目的只是列印字串值,則可以使用fmt.Sprint,它使用反射。
對于更廣泛的情況,當引數可以采用精確型別為string(without ~) 和時,colm.anseo 的答案中的型別斷言或 switch 作業得很好fmt.Stringer。對于近似值,~string 您無法詳盡處理所有可能的術語,因為這些型別集實際上是無限的。所以你又回到了反思。更好的實作可能是:
func StringLike(v any) string {
// switch exact types first
switch s := v.(type) {
case fmt.Stringer:
return s.String()
case string:
return s
}
// handle the remaining type set of ~string
if r := reflect.ValueOf(v); r.Kind() == reflect.String {
return r.String()
}
panic("invalid type")
}
游樂場:https ://go.dev/play/p/-wzo2KPKzWZ
uj5u.com熱心網友回復:
泛型——理論上允許使用多種型別——在編譯時確定一個具體的型別。介面在運行時允許多種型別。您希望同時將這兩者結合起來——不幸的是,這是不可能的。
不使用反射可以獲得的最接近的方法是使用運行時型別斷言:
func StringLike(v any) string {
if s, ok := v.(string); ok {
return s
}
if s, ok := v.(fmt.Stringer); ok {
return s.String()
}
panic("non string invalid type")
}
https://go.dev/play/p/p4QHuT6R8yO
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/477885.html
上一篇:在C#中將類重構為多層泛型類
下一篇:不變泛型似乎無法正常作業
