考虑以下代码
import "fmt"
type key1 int
type key2 string
type value int
type m1 map[key1]value
type m2 map[key2]value
type A[key key1 | key2, t ~map[key]value] struct {
m t
}
// I chose an example involving looping through a map to highlight the need of defining the map itself in the constraint.
func (a A[t, key]) foo() {
for k, v := range a.m {
fmt.Println(k, v)
}
}
func main() {
A[key1, m1]{
m: m1{1: 1},
}.foo() // prints: 1 1
A[key2, m2]{
m: m2{"one": 1},
}.foo() // prints: one 1
}
在更复杂的设置中,我需要编写一个更长的“通用表达式”,并且需要重复多次(每个方法一次)。因此,我很乐意用更短的表达来代替它。我尝试过类似的事情
type constrainKey interface {
key1 | key2
}
type constrainMap interface {
map[constrainKey]value
}
type A[t constrainMap] struct {
m t
}
func (a A[constrainMap]) foo() {
for k, v := range a.m {
fmt.Println(k, v)
}
}
但是编译失败。你能帮我找到一个更短/更简单的约束表达式吗?帮我找到一个可以单独表示约束的接口定义
key key1 | key2, t ~map[key]value
。
这里无法简化实例化。
只要您想要参数化键类型,就必须为其指定单独的类型参数。只要结构体定义上有两个类型参数,就必须始终实例化它们。
有一个关于将类型推断扩展到泛型类型的未决问题,但该语言尚不支持它。
类型推断确实适用于函数。因此,唯一可能的解决方法是定义一个接受泛型类型作为参数的函数:
func DoFoo[K key1 | key2, M ~map[K]value](m M) {
A[K, M]{
m: m,
}.foo()
}
然后用所需的参数调用它:
func main() {
Foo(m1{1: 1})
Foo(m2{"one": 1})
}
显然,您始终可以从此函数返回
A
,以防以后需要使用该结构。
func DoFoo[K key1 | key2, M ~map[K]value](m M) A[K, M] {
a := A[K, M]{
m: m,
}
a.foo()
return a
}