Go语言 使用反射从泛型结构获取类型参数

piok6c0g  于 2022-12-07  发布在  Go
关注(0)|答案(3)|浏览(264)

假设我有以下结构:

type MyGeneric[T string | int] struct {
}

我想在创建新的MyGeneric时检查用于示例化该结构的泛型是字符串还是整型。

myGenericString := MyGeneric[string]{}
myGenericString.canHandle("hello") -> should return true
myGenericString.canHandle(8) -> should return false

func (mG MyGeneric[T]) canHandle(value any) bool {
    // how to get what T is the same type as value
}
w6lpcovy

w6lpcovy1#

还没有实现,有一个open proposal,关于给reflect.Type添加必要的方法。
从Go语言1.19开始,目前的解决方法是解析从TypeOf中得到的字符串,如下所示:

var r = regexp.MustCompile("[A-Za-z0-9_]+\\.[A-Za-z0-9_]+\\[(.*)\\]")

func (mG MyGeneric[T]) typeParam(value any) {
    tname := reflect.TypeOf(mG).String() // this is `main.MyGeneric[string]`
    match := r.FindStringSubmatch(tname)
    fmt.Println(match[1]) // string
}

如果目标只是获取类型参数的名称,那么这并不好,因为它依赖于类型的字符串表示。从好的方面来说,它不会强迫你考虑如果用接口示例化T会发生什么。
如果您需要对T类型做进一步的计算,例如,将其与其他类型进行比较等,@SOFe的答案提供了一个不依赖于任意字符串表示的解决方案。
但是,请注意使用接口示例化的T:另请参阅In Golang, how to compare interface as generics type to nil?

tktrz96b

tktrz96b2#

只需直接示例化T以获取其值。

type MyGeneric[T any] struct {
}

func (mG MyGeneric[T]) canHandle(value any) bool {
    var t T
    tt := reflect.TypeOf(t)

    vt := reflect.TypeOf(value)

    fmt.Printf("-> %v == %v\n", tt, vt)
    return tt == vt
}

type empty struct{}

func main() {
    fmt.Printf("%v\n", MyGeneric[string]{}.canHandle(""))
    fmt.Printf("%v\n", MyGeneric[string]{}.canHandle(1))
    fmt.Printf("%v\n", MyGeneric[MyGeneric[struct{}]]{}.canHandle(MyGeneric[struct{}]{}))
    fmt.Printf("%v\n", MyGeneric[MyGeneric[struct{}]]{}.canHandle(MyGeneric[empty]{}))
}

输出量:

-> string == string
true
-> string == int
false
-> main.MyGeneric[struct {}] == main.MyGeneric[struct {}]
true
-> main.MyGeneric[struct {}] == main.MyGeneric[main.empty]
false

如果您担心T分配了太多未使用的堆栈,请将其改为数组:

var tArr [0]T
tt := reflect.TypeOf(tArr).Elem()
nue99wik

nue99wik3#

另一个解决方案是在你的结构体中添加一个placeHolder字段,它可以用来通过类型开关获取它的类型,以避免反射:

type MyGeneric[T string | int] struct {
  placeHolder T
}

func (mG MyGeneric[T]) canHandle(value any) bool {
    switch t1 := any(p.placeHolder).(type) {
    case any:
        switch t2 := value.(type) {
        case any:
            return t1 == t2
        }
    }
    return false
}

相关问题