Go语言 获取不带类型参数的泛型结构的类型名称

nvbavucw  于 2022-12-20  发布在  Go
关注(0)|答案(1)|浏览(128)

假设我有一个名为foo的泛型结构体,我用它创建了两个对象,我可以使用reflect.TypeOf()确定每个对象的具体类型,如下所示:

package main

import (
    "fmt"
    "reflect"
)

type foo[T any] struct {
    data T
}

func main() {
    a := foo[string]{"cheese"}
    b := foo[int]{42}

    fmt.Println(reflect.TypeOf(a))
    fmt.Println(reflect.TypeOf(b))
}

// main.foo[string]
// main.foo[int]

我感兴趣的是只确定这些对象的泛型类型(即foo),而不是具体类型(即foo[string]foo[int])。这是可能的,还是需要手动从这些字符串中提取泛型类型(例如,使用regex)?

编辑

正则表达式可能如下所示:

func GetGenericType(x any) string {
    // Get type as a string
    s := reflect.TypeOf(x).String()

    // Regex to run
    r := regexp.MustCompile(`\.(.*)\[`)

    // Return capture
    return r.FindStringSubmatch(s)[1]
}

fmt.Println(GetGenericType(a))
fmt.Println(GetGenericType(b))

// foo
// foo

我也看过this question,但这没有回答这个问题,因为它给出了 * 具体 * 类型(即main.foo[string]),而不是泛型类型(即foo)。

ddrv8njm

ddrv8njm1#

反射看不到“基”泛型类型的名称,因为在运行时该基类型不存在。
Go语言规范中的相关段落是示例化:
示例化类型会产生新的非泛型命名类型;示例化函数产生新的非泛型函数。
所以当你写:

b := foo[int]{42}
name := reflect.TypeOf(b).Name()

该类型的名称正好是foo[int]
值得注意的是,没有类型参数列表的 identifierfoo在编译时是相关的,因为它阻止了你在同一个包中重新声明它。类型定义:
类型定义创建一个与给定类型具有相同底层类型和操作的新的不同类型,并将标识符(类型名)绑定到它

TypeDef = identifier [ TypeParameters ] Type .

但是如上所定义的示例化导致不同于foo的新命名类型;在运行时,当您可以使用反射时,您只处理示例化。
总之,我认为使用regex的解决方案是可以接受的,除非向stdlib添加一些辅助函数(如果有的话)。
请记住Type.String()Type.Name()之间的区别:任何类型都可以有一个字符串表示,但是只有命名类型才有一个名称。(很明显,对吗?)例如,如果你写:

b := &foo[int]{42}

那么b的类型是*foo[int],它是匿名复合类型,并且Name()返回空字符串。

相关问题