Go 函数创建泛型类型的新指针或新值

标签 go pointers generics

我有一个函数,它采用泛型类型,并且应该返回一个始终返回指针的函数。 IE。如果你传递给它一个非指针类型,它应该返回一个指向该类型的指针,如果你传递给它一个指针类型,它应该返回相同的类型。我不想使用 reflect.New,因为它是一个性能关键型应用。

我不介意在返回工厂函数的函数中使用反射,但理想情况下甚至不在那里。

这就是我正在尝试做的事情:

package main

import (
    "fmt"
    "reflect"
)

type Ptr[T any] interface {
    *T
}

func makeNewA[T Ptr[U], U any]() any {
    return new(U)
}

func makeNewB[T any]() any {
    return new(T)
}

func makeNew[T any](v T) func() any {
    if reflect.TypeOf(v).Kind() == reflect.Ptr {
        return makeNewA[T] // <-- error: T does not match *U
    } else {
        return makeNewB[T]
    }
}

type Foo struct{}

func main() {
    make1 := makeNew(Foo{})
    make2 := makeNew(&Foo{})

    // should both return &Foo{}
    fmt.Println(make1())
    fmt.Println(make2())
}

最佳答案

这种条件类型不能用泛型很好地解决,因为当您使用 *Foo 实例化 Tany 时,您会丢失有关基本类型的信息。事实上,您的代码仍然使用反射和 any (= interface{}),并且 makeN 函数的返回类型必须类型断言为 *Foo

您可以使用当前代码得到的最接近的是:

func makeNew[T any](v T) func() any {
    if typ := reflect.TypeOf(v); typ.Kind() == reflect.Ptr {
        elem := typ.Elem()
        return func() any {
            return reflect.New(elem).Interface() // must use reflect
        }
    } else {
        return func() any { return new(T) } // v is not ptr, alloc with new
    }
}

然后两个生成器函数都会返回一个包含非零 *Foo 值的 any :

fmt.Printf("%T, %v\n", make1(), make1()) // *main.Foo, &{}
fmt.Printf("%T, %v\n", make2(), make2()) // *main.Foo, &{}

Playground :https://gotipplay.golang.org/p/kVUM-qVLLHG

进一步考虑:

  • return makeNewA[T] 在第一次尝试中不起作用,因为条件 reflect.TypeOf(v).Kind() ==reflect.Ptr 的计算结果为makeNewA 的实例化发生在编译时。在编译时,T 仅受 any 约束,并且 any (= interface{}) 未实现Ptr[U]
  • 仅使用参数 v 无法捕获有关指针类型和基类型的信息。例如,使用 makeNew(Foo{})makeNew[ 调用时,makeNew[T Ptr[U], U any](v T) 将无法编译当用 *Foo 调用时,T Ptr[U], U any](v U) 会将 T 推断为 **Foo

关于Go 函数创建泛型类型的新指针或新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71443373/

相关文章:

Golang - 丢弃为 WriteCloser

go - image.Decode 在解码 .png 文件时返回错误

时间:2018-01-08 标签:c++oop: function pointer table

更改函数中指针引用的变量

c++ - 返回 char** 或传递 char* 数组

date - 如何将日期转换为不同的格式?

json - 在 Go 中创建结构以从 API 中读取

c# - 为什么这个泛型在编译时没有解析?

java - 为什么这些类型不兼容赋值,如何定义赋值兼容的类?

java - 如何将泛型传递给 Spring CRUD 存储库的 save 方法