我有一个函数,它采用泛型类型,并且应该返回一个始终返回指针的函数。 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/