
使用 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。










