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 关注
- 118 浏览
添加回答
举报