我目前在Go上遇到了一个问题,我想创建一个通用函数,接受T的切片,其中*T实现了一些接口.然而,我不确定如何使用Go的仿制药来实现这一目标.

// Lets say this is the interface I want to use
type Foo interface {
    DoFoo()
}

type Bar struct {
    x int
}

// The issue is Foo must be implemented on a type's pointer
func (bar *Bar) DoFoo() {
    bar.x += 1
}

// How can I make a generic function for any slice of Foo?
func DooFooForBarSlice(bars []Bar) {
    // This is a hot loop, so performance is important
    for index := 0; index < len(bars); index++ {
        bars[index].DoFoo()
    }
}

由于内存和性能问题,要求使用指针切片不是一种 Select (项目相当小,而切片非常大).

如果一般性不起作用,我知道我可以用反射来实现它,但为了可读性,我试图避免这种情况,而且我对反射缺乏理解会影响性能.

推荐答案

您必须使指针接收器成为显式约束:

type FooPtr[T any] interface {
    Foo
    *T
}

*Bar满足FooPtr[Bar],因此在DooFooForBarSlice的定义中使用它:

func DooFooForBarSlice[T any, PT FooPtr[T]](bars []T) {
    for index := 0; index < len(bars); index++ {
        ((PT)(&bars[index])).DoFoo()
    }
}

playground :https://go.dev/play/p/HY6IfixI0vq

Go相关问答推荐

如何在gofr发起的服务间调用请求中添加Authorization Header?

为什么Slices包中的函数定义Slice参数的类型参数?

mockgen不创建模拟

Wamtime Memory中的‘Offset’是什么?Read?

无法读取postman 中的表单数据

Kubo,来自 IpfsNode.Bootstrap 的无效内存地址或零指针取消引用

无法将 graphql-ws 连接到 gqlgen

Go 切片容量增长率

我如何使用 TOML fixtures 在使用 Go Buffalo 框架的开发环境中为我的数据库 seeder ?

在嵌套模板中使用变量,它也被定义为 go 模板中的变量?

Gorm 预加载给出了模糊的列错误

如何在 Docker 容器中使用私有存储库进行身份验证

Go gmail api 快速入门导致本地主机拒绝连接 ERR_CONNECTION_REFUSED

fmt.Printf() 标志 '0' 不会被字符串忽略

使用innerxml在 Go 中编码 XML 是否仅适用于某些类型?

如何将文件上传到 Google Drive,并与使用服务帐户和 Golang 的任何人共享

合并几千万文件最快的方法是什么

vs 代码调试 go 测试不通过标志

在 VSCode 中使用命令行参数调试 Go 测试

不能使用 *T 类型的变量作为参数类型