登录
首页 >  Golang >  Go问答

结合接口和实现的 Golang 泛型

来源:stackoverflow

时间:2024-03-24 15:00:43 281浏览 收藏

在 Go 语言中使用泛型时,当将接口和实现约束为泛型类型参数时,会出现问题。当泛型类型参数 x 和 y 都约束为 any 时,编译器无法识别接口和实现之间的关系,导致赋值失败。虽然可以通过使用显式断言解决编译错误,但可能会引发恐慌或丢失基本类型信息。本文建议使用构造函数代替第二个类型参数,作为在泛型上下文中初始化接口的更可靠方法。

问题内容

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

func fill[x any](slice []*x){
   for i := range slice {
      slice[i] = new(x)
   }
}

xs := make([]*int, 10) // fill with nils
fill(xs) // now fill with new(int)

这很好用,但是……如果我想使用一部分接口并提供具体类型?

func Fill[X, Y any](slice []X){
   for i := range slice {
      slice[i] = new(Y) // not work!
   }
}

xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch

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


正确答案


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

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

func fill[x, y any](slice []x) {
    for i := range slice {
        slice[i] = any(*new(y)).(x)
    }
}

但是,如果 y 没有真正实现 x如您的情况,则会出现恐慌,因为它是 *sync.mutex (指针类型)实现 sync。 locker

此外,当使用指针类型实例化 y 时,您会丢失有关基本类型的信息,因此零值(包括 *new(y) )将是 nil,因此您并没有真正获得基线改进通过 make (只需输入 nils 与 nil 接口)。

您想要做的是将 y 约束为 x,例如 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()
    }
}

本篇关于《结合接口和实现的 Golang 泛型》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>