有没有办法在Go中列出泛型 struct /接口?

这就是我想要实现的目标.

package main

type List[T any] struct {
    Elements []T
}

func (f *List[T]) Add(el T) {
    f.Elements = append(f.Elements, el)
}

type ListInterface[T any] interface {
    Add(el T)
}

func main() {
    listOfLists := make([]ListInterface[any], 0)
    listOfLists = append(listOfLists, &List[int]{})
}

以下是我得到的错误.

cannot use &List[int]{} (value of type *List[int]) as ListInterface[any] value in argument to append: *List[int] does not implement ListInterface[any] (wrong type for method Add)
    have Add(int)
    want Add(any)

所以,如果我理解正确的话,围棋any是它自己的类型.它不是"在运行时想要的任何类型"的同义词.我的问题是,有没有可能做这样的事情?

推荐答案

您在这里try 做的事情表明您期望GO的泛型是类型擦除的(就像Java泛型一样).然而,它们并非如此.

你有一个List[int],这意味着它的Add方法如下所示:

func (l *List) Add(el int) {
    l.Elements = append(l.Elements, el)
}

然后,try 将此代码添加到实现该接口的一组对象中:

Add(v any)

现在,你可能认为int可以用作any,你是对的,它可以,但当你看到:

var s []ListInterface[any]

您的意思是说,所述片中的所有元素都将有一个接受any类型参数的Add方法,因此这意味着:

s[0].Add("foo")
s[1].Add(123)

应该总是有效的电话.如果s[0]的类型是List[int],就像你的代码片段中的情况一样,这不成立.你将try 向Elements追加一个类型为[]int的字符串.

有一种说法认为,应该允许相反的情况:

s := []ListInterface[int]{}
s = append(s, &List[any]{})

Seed as List[any]将接受int参数,但这也是不允许的.在某些情况下,这可能是有用的,但在许多情况下,这可能是有问题的.

本质上,Go中的泛型是在编译时处理的东西.当您创建一个List[int]时,编译器将创建一个类似List_int的类型,并在该类型上实现Add(el int)方法,就像它将对您最终使用的任何其他List类型一样.除非您创建List[any],否则这些类型都不会有Add(any)方法.可以将其视为编译器辅助的模板代码生成.不是运行时类型擦除.

结果是:List[int]List[any]是完全不同的类型,因此不能在一个切片中并排坐在一起,就像它们是同一类型一样.如果你想做你想做的事情,你可以这样做:

func (l *List[T]) AddAny(v any) {
    tv, ok := v.(T)
    if !ok {
        return // or return an error
    }
    l.Add(tv)
}

接受any值的方法,使用类型断言查看给定值是否与列表的基础类型兼容,如果是,则添加该值.然后,您可以将它们添加到如下所示的单个切片中:

type Lists interface {
    AddAny(any)
}

s := []Lists{}
s = append(s, &List[int]{}, &List[string]{})
s[0].AddAny(123) // will work
s[0].AddAny("foo") // will not, with the current code this will silently fail
s[1].AddAny("foo") // works fine
s[1].AddAny(123) // silently fails

但实际上,当您做这样的事情时,代码只是尖叫着X-Y问题,其中您试图使用Y(泛型)来解决问题,而真正的问题是X:解决问题的最佳方法是什么?

Go相关问答推荐

"k8s.io/apimachinery/pkg/runtime.对象(缺少方法DeepCopyBody)

Go Fiber和HTMX—HX—Trigger header被更改为HX—Trigger,这不是HTMX监听的内容

将Go程序导出到WASM—构建约束排除所有Go文件

如何在AWS SDK Go v2 STS上正确使用重试

Golang html/模板&需要错误数量的参数1在模板中使用';调用';获得0&q;

如何使用GO GIN从Auth0 JWT内标识检索权限

MaybeReadByte对通道的使用如何在Go中提供随机行为?

Go SQLCMD比Windows本机版本慢吗?

golang regex基于关键字拆分字符串

为什么要立即调用内联函数,而不仅仅是调用其包含的函数?

你如何在 Golang 代码中测试 filepath.Abs​​ 失败?

如何使用 go-git 将特定分支推送到远程

在 Gorm 的 AfterFind() 钩子中获取智能 Select struct 的值

当有多个同名包时如何在vscode中显示golang包完整路径?

分配空切片而不引用其类型?

Unescape 在 rss 中两次逃脱了标题

golang 如何从字符串中查找表情符号?

Scanner.Buffer - 最大值对自定义拆分没有影响?

如何动态解析 Go Fiber 中的请求正文?

Go 错误:cannot use generic type without instantiation