同时具有接口和实现的 Golang 泛型

Tia*_*nyj 5 generics go

我正在尝试编写以下函数:

\n
func Fill[X any](slice []*X){\n   for i := range slice {\n      slice[i] = new(X)\n   }\n}\n\nxs := make([]*int, 10) // fill with nils\nFill(xs) // now fill with new(int)\n
Run Code Online (Sandbox Code Playgroud)\n

这工作正常,但是\xe2\x80\xa6 如果我想使用一部分接口并提供具体类型?

\n
func Fill[X, Y any](slice []X){\n   for i := range slice {\n      slice[i] = new(Y) // not work!\n   }\n}\n\nxs := make([]sync.Locker, 10) // fill with nils\nFill[sync.Locker,sync.Mutex](xs) // ouch\n\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试了一些组合没有成功,有没有办法或者go1.18不支持这样的关系?

\n

bla*_*een 4

当您将XY限制为 时any,您将失去所有接口-实现者关系。在编译时唯一知道的是XY是不同的类型,并且您不能在函数体内将一个类型分配给另一个类型。

使其编译的一种方法是使用显式断言:

func Fill[X, Y any](slice []X) {
    for i := range slice {
        slice[i] = any(*new(Y)).(X)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果Y没有真正实现X就像您的情况一样,这会引起恐慌,因为它是*sync.Mutex(指针类型)实现的sync.Locker

此外,当Y使用指针类型实例化 时,您会丢失有关基本类型的信息,因此会丢失零值,包括*new(Y)will be nil,因此您实际上并没有比make(仅键入 nils 与 nil 接口)有基线改进。

想要做的是约束YX, ,Fill[X any, Y X](slice []X)但这是不可能的,因为 1) 类型参数不能用作约束;和/或 2) 约束不能直接嵌入类型参数。它还像上面一样初始化 nils。

更好的解决方案是使用构造函数而不是第二个类型参数:

func main() {
    xs := make([]sync.Locker, 10)
    Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}

func Fill[X any](slice []X, f func() X) {
    for i := range slice {
        slice[i] = f()
    }
}
Run Code Online (Sandbox Code Playgroud)