
使用 go 的 reflect 包可动态获取传入参数的结构体或接口类型名,关键在于通过 `reflect.valueof()` 获取值的反射对象,并调用 `type().name()` 或更鲁棒的 `type().String()` 提取类型名称。
在 go 中,运行时获取任意值的类型名称(如 “User”)需借助 reflect 包。由于 Go 是静态类型语言,编译期类型信息在运行时可通过反射机制访问。但需注意:reflect.Type.Name() 仅对命名类型(即包内直接定义的 Struct、Interface)返回非空字符串;对于指针、切片、匿名结构体或未导出类型,它可能返回空字符串。
以下是一个健壮的实现示例:
package main import ( "fmt" "reflect" "./crud" ) func get_struct(value interface{}) { v := reflect.ValueOf(value) if !v.IsValid() { fmt.Println("nil") return } t := v.Type() // 推荐:使用 String() 获取完整、可读的类型描述(含包名和指针符号) // 例如:*crud.User → "*crud.User";crud.User → "crud.User" fmt.Println("Type.String():", t.String()) // 补充:若仅需结构体名(不含包名和指针),可递归解引用后取 Name() for t.kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.map { t = t.Elem() } name := t.Name() if name == "" { fmt.Println("Type.Name(): (anonymous or unnamed)") } else { fmt.Println("Type.Name():", name) } } func main() { get_struct(&crud.User{}) // 输出: Type.String(): *crud.User;Type.Name(): User get_struct(crud.User{}) // 输出: Type.String(): crud.User;Type.Name(): User }
✅ 关键要点说明:
- reflect.ValueOf(x).Type().String() 是最安全的选择,能准确反映实际类型(包括 *T、[]T、map[K]V 等),且始终返回非空字符串;
- reflect.ValueOf(x).Type().Name() 仅对具名类型(named type) 有效,对指针、切片等复合类型返回空字符串 —— 因为 *User 本身不是命名类型,User 才是;
- 若需剥离指针/包装层获取底层结构体名,应循环调用 t.Elem() 直至 Kind() 不再为 reflect.Ptr 等;
- 注意:reflect 带来一定性能开销,不建议在高频路径中滥用;生产环境若类型已知,优先使用类型断言或泛型替代。
总结:动态获取类型名应首选 Type.String(),辅以 Elem() 解包逻辑按需提取简洁名称,同时始终校验 IsValid() 避免 panic。