2 回答

TA貢獻1829條經驗 獲得超7個贊
混淆可能是有道理的,因為類型參數提案建議像你的代碼,但最終成為 Go 1.18 中的實現限制。
它在specs和 Go 1.18 發行說明中提到。規格是規范參考:
實現限制:一個聯合(多于一個術語)不能包含預先聲明的標識符
comparable
或指定方法的接口,或嵌入comparable
或指定方法的接口。
對于為什么這沒有包含在 Go 1.18 版本中,也有一些廣泛的解釋。tl;dr 簡化了聯合類型集的計算(盡管在 Go 1.18 中,類型參數的方法集也不是隱式計算的......)。
還要考慮,無論有沒有這個限制,除了傳遞給使用反射的函數之外,您可能不會獲得任何有用的東西T
。要調用方法,~string | fmt.Stringer
您仍然必須進行類型斷言或類型切換。
請注意,如果這種約束的目的只是為了打印字符串值,您可以只使用fmt.Sprint
,它使用反射。
string
對于更廣泛的情況,當參數可以采用(without ~
) 和 等確切類型時,如 colm.anseo's answer 中的類型斷言或開關工作得很好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

TA貢獻1810條經驗 獲得超5個贊
泛型——理論上允許使用多種類型——在編譯時選擇單一的具體類型。接口允許在運行時使用多種類型。您希望同時將這兩者結合起來——不幸的是,這是不可能的。
在不使用反射的情況下,最接近的方法是使用運行時類型斷言:
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
- 2 回答
- 0 關注
- 131 瀏覽
添加回答
舉報