1 回答

TA貢獻2012條經驗 獲得超12個贊
它在非常罕見的情況下是相關的,在這種情況下,您需要聲明一個函數類型的變量(而不調用它),并且您使用另一個在其定義中使用未導出類型的包中的命名映射類型實例化該函數。
當您需要接受和返回定義的類型時,在函數簽名中使用命名類型參數最相關,正如您正確猜測的那樣,正如@icza在此處回答的關于x/exp/slices
包的問題。
您關于“代字號類型”只能用于接口約束的說法也是正確的。
現在,包中的幾乎所有函數x/exp/maps
實際上并不返回命名類型M
。唯一真正做到的是maps.Clone
帶有簽名:
func Clone[M ~map[K]V, K comparable, V any](m M) M
然而,由于類型統一,在沒有近似約束的情況下聲明簽名仍然適用于定義的類型。從規格:~map[K]V
[...],因為定義
D
的類型和類型文字L
永遠不會等價,統一將 D 的基礎類型與 L 進行比較
和一個代碼示例:
func Keys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
type Dictionary map[string]int
func main() {
m := Dictionary{"foo": 1, "bar": 2}
k := Keys(m)
fmt.Println(k) // it just works
}
游樂場:https ://go.dev/play/p/hzb2TflybZ9
附加命名類型參數M ~map[K]V相關的情況是當您需要傳遞函數的實例化值時:
func main() {
// variable of function type!
fn := Keys[Dictionary]
m := Dictionary{"foo": 1, "bar": 2}
fmt.Println(fn(m))
}
游樂場:https ://go.dev/play/p/hks_8bnhgsf
如果沒有M ~map[K]V類型參數,就不可能用定義的類型實例化這樣一個函數值。當然你可以實例化你K的V函數
fn := Keys[string, int]
但是當定義的映射類型屬于不同的包并引用未導出的類型時,這是不可行的:
package foo
type someStruct struct{ val int }
type Dictionary map[string]someStruct
和:
package main
func main() {
// does not compile
// fn := Keys[string, foo.someStruct]
// this does
fn := maps.Keys[foo.Dictionary]
}
雖然,這似乎是一個相當通俗的用例。
你可以在這里看到最終的游樂場:https ://go.dev/play/p/B-_RBSqVqUD
但是請記住,這x/exp/maps是一個實驗包,因此簽名可能會隨著未來的 Go 版本和/或當這些函數被提升到標準庫中而改變。
- 1 回答
- 0 關注
- 145 瀏覽
添加回答
舉報