为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
陪伴而非守候 2022-11-23 10:24:15

我有一个采用泛型类型的函数,应该返回一个始终返回指针的函数。也就是说,如果你传递给它一个非指针类型,它应该返回一个指向该类型的指针,如果你传递给它一个指针类型,它应该返回相同的类型。我不想使用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())

}


查看完整描述

1 回答

?
阿波罗的战车

TA贡献1576条经验 获得超6个赞

这种条件类型不能用泛型很好地解决,因为当你用它实例化时T any,*Foo你会丢失关于基类型的信息。事实上,您的代码仍然使用反射和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

    }

}

然后两个 maker 函数将返回一个any包装非 nil*Foo值的:


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

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

游乐场: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[T Ptr[U], U any](v T),调用 with 时不会编译,调用 with时makeNew(Foo{})将makeNew[T Ptr[U], U any](v U)推断T为**Foo*Foo


查看完整回答
反对 回复 2022-11-23

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信