我在 Go 1.21 中使用泛型。我想扩展一些通用代码。
如果我将下面的
foo()
添加到Under11AgeGroups
接口中,这样只有9岁以下和11岁以下的人必须实现此功能,我会收到编译错误:
不能在联合中使用带有方法的接口。
我是否缺少一种方法来做到这一点?
以下代码运行。
https://go.dev/play/p/w_N7gbsRCjY
package main
import (
"fmt"
)
type AllAgeGroups interface {
Under13Player | Under11AgeGroups
name() string
}
type Under11AgeGroups interface {
Under9Player | Under11Player
// foo() string <-- this causes cannot use main.Under11AgeGroups in union (main.Under11AgeGroups contains methods)
}
type Players[T AllAgeGroups] struct {
Results []T
}
func (t *Players[T]) PrintTheTeam() {
fmt.Println("----------------")
for _, p := range t.Results {
fmt.Println("Player ", p.name())
}
}
type Under9Player struct { Name string }
func (u Under9Player) name() string {
return u.Name
}
type Under11Player struct { Name string }
func (u Under11Player) name() string {
return u.Name
}
type Under13Player struct { Name string; Age int }
func (u Under13Player) name() string {
return u.Name + " " + string(u.Age)
}
func main() {
bob := Under11Player{Name: "bob"}
alice := Under11Player{Name: "alice"}
yves :=Under11Player{Name: "yves"}
under11team := Players[Under11Player]{Results: []Under11Player{bob, alice, yves}}
under11team.PrintTheTeam()
foo :=Under13Player{Name: "foo", Age: 12}
under13team := Players[Under13Player]{Results: []Under13Player{foo}}
under13team.PrintTheTeam()
}
您不能直接将方法添加到已出现在联合术语中的接口。这是语言规范所禁止的(关于接口类型的段落):
实现限制:联合(具有多个术语)不能包含预先声明的标识符比较或指定方法的接口,也不能嵌入比较或指定方法的接口。
不过有一个窍门!由于您使用这些接口作为约束,因此它们提供了编译时检查。您可以通过尝试实例化限制为具有所需类型的方法的类型参数来复制该编译时检查:
type Under11AgeGroups interface {
Under9Player | Under11Player
// these should both have a `foo() string` method
}
// dummy function with type parameter that must have the foo() string method
func mustDefineFoo[T interface{ foo() string }]() {}
// dummy instantiations with the desired types
var _ = mustDefineFoo[Under9Player]
var _ = mustDefineFoo[Under11Player]
注意
mustDefineFoo[Under9Player]
是函数值。实际上它们是什么并不重要,它们的存在只是为了强制编译器检查 Under9Player
和 Under11Player
是否满足约束:如果它们具有 foo() string
方法,它们就会满足约束。
游乐场:https://go.dev/play/p/2QXzMsw1Qld
显然,每次向主界面约束添加一个新术语时
Under11AgeGroups
,您都必须向源代码中添加一个新的虚拟实例化,但这与向现有联合添加一个术语没有太大区别。