Go语言 如何将方法添加到已在联合项中使用的接口?

5w9g7ksd  于 5个月前  发布在  Go
关注(0)|答案(1)|浏览(39)

我在Go 1.21中使用泛型。我想扩展一些通用代码。
如果我将下面的foo()添加到Under11AgeGroups接口中,那么只有9岁以下和11岁以下的人必须实现这个函数,我会得到一个编译错误:
不能将接口与union中的方法一起使用。
我错过了一个方法来做到这一点吗?
下面的代码运行。
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()
    }

字符串

cnwbcb6i

cnwbcb6i1#

你不能直接向已经出现在union项中的接口添加方法。这是语言规范禁止的(关于接口类型的段落):
实施限制:联合(具有多个术语)不能包含预先声明的标识符comparable或指定方法的接口,或嵌入comparable或指定方法的接口。
不过,有个窍门!由于你使用这些接口作为约束,它们提供了编译时检查。你可以通过尝试示例化一个类型参数来复制编译时检查,该类型参数被约束到具有所需类型的方法:

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]是函数值。实际上这些值是什么并不重要,它们的存在只是为了强制编译器检查Under9PlayerUnder11Player是否满足约束:如果它们有foo() string方法,它们就满足约束。
Playground:https://go.dev/play/p/2QXzMsw1Qld
显然,每次向主接口约束Under11AgeGroups添加一个新项时,都必须向源代码中添加一个新的虚拟示例化,但这与向现有联合体中添加一个新项没有太大区别。

相关问题