這兩個函式有什么區別?
func f[_ string, p string](s ...p) {
fmt.Println(s)
}
func f[p string](s ...p) {
fmt.Println(s)
}
為什么首先要在型別引數中放置一個空白識別符號?
uj5u.com熱心網友回復:
使用下劃線_代替型別引數名稱只是表明該型別引數未在函式范圍內使用。
在您的示例代碼中,它并沒有真正的區別;的兩個版本都f可以在f("blah")不提供顯式型別引數的情況下呼叫。但這只是可能的,因為約束string限制為確切的型別。它只能是string,所以型別推斷仍然有效。
如果將其更改為近似型別,則必須顯式實體化:
// can't infer first type param from anywhere
func f[_ ~string, P ~string](s ...P) {
fmt.Println(s)
}
func main() {
// must supply first type param, may omit second one
f[string]("blah")
}
在約束不是精確型別的實際場景中,下劃線可能會強制呼叫者指定型別引數:這實際上會破壞向后兼容性,因為客戶端代碼確實必須更新才能作業。
需要明確的是,這適用于相互獨立的型別引數。如果下劃線型別引數可以從另一個型別引數推斷出來,它仍然可以在沒有顯式實體化的情況下編譯:
// called as foo("blah")
func foo[T ~string, P *T](t T) {
var p P = &t
fmt.Println(t, p)
}
// still called as foo("blah")
func foo[T ~string, _ *T](t T) {
fmt.Println(t)
}
然而值得注意的是,如果一個函式有兩個獨立的型別引數,可以從引數中推斷出來:
func f[T any, U any](t T, u U) {
fmt.Println(t, u)
}
...使U不可推斷也意味著也洗掉了u U論點,因此您已經有了向后不兼容的更改。
// one less argument, requires major version upgrade anyway
func foo[T any, _ any](t T) {
fmt.Println(t, u)
}
相反,使用方法,情況就不同了。由于方法不能指定未在接收器型別上宣告的型別引數,因此使用下劃線的情況要頻繁得多。某些方法可能不需要所有型別引數。然后下劃線恰當地反映了這一點:
type Foo[T,U any] struct {
ID T
Val U
}
// we do not need to reference U here
func (f *Foo[T,_]) SetID(t T) {
f.ID = t
}
// we do not need to reference T here
func (f *Foo[_,U]) SetVal(v U) {
f.Val = v
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/460184.html
上一篇:根據型別從泛型呼叫動態函式
