reflect.TypeOf() 返回变量声明时的静态类型,对 interface{} 返回其底层 concrete type;nil 接口返回 nil,需防 panic;Name() 对匿名/内建类型为空,Kind() 更稳定;优先用类型断言而非反射。

用 reflect.TypeOf() 获取变量的静态编译时类型
Go 是静态类型语言,reflect.TypeOf() 返回的是变量声明时的类型(即接口底层的 concrete type),不是运行时“动态变化”的类型。它对 interface{} 类型尤其关键:传入一个 int 值给 interface{},reflect.TypeOf() 返回的是 int,不是 interface{}。
- 如果变量是未初始化的 nil 接口,
reflect.TypeOf(nil)返回nil,直接调用.Name()或.Kind()会 panic - 对指针、切片、map 等复合类型,
Type.Name()可能为空(如匿名结构体、内建类型),此时应优先用Type.Kind() -
Type.String()返回完整类型字符串(含包路径),适合日志调试;Type.Kind()返回基础分类(reflect.Struct、reflect.Ptr等),适合分支判断
用 reflect.ValueOf() 安全读取值并识别底层类型
reflect.ValueOf() 返回的是值的反射表示,但必须配合 .IsValid() 和 .CanInterface() 使用,否则容易 panic。尤其当传入 nil 指针或未导出字段时,操作会失败。
- 对 nil 指针调用
.Elem()会 panic,必须先用.Kind() == reflect.Ptr && !v.IsNil()判断 - 从
interface{}取值后,若原值是不可寻址的(如字面量、函数返回值),.Addr()不可用,.CanAddr()返回 false - 要获取真实值,推荐链式判断:
if v := reflect.ValueOf(x); v.IsValid() { switch v.Kind() { case reflect.String: s := v.String() case reflect.Int, reflect.Int64: i := v.Int() } }
区分 reflect.Type 的 Name() 和 Kind()
Name() 只对命名类型(如 type MyInt int)返回非空字符串;内建类型(int、string)、匿名 struct、闭包函数等都返回空。而 Kind() 总是返回底层分类,稳定可靠。
- 错误写法:
if t.Name() == "time.Time" {...} // ❌ time.Time.Name() 是空字符串 - 正确写法:
if t.Kind() == reflect.Struct && t.PkgPath() == "time" && t.Name() == "Time" {...} // ✅ 或更稳妥地用 t.String() 匹配 - 常见误判场景:自定义类型
type Status uint8,t.Kind()是reflect.Uint8,不是reflect.Uint8的别名——Go 中类型别名(type Status = uint8)才共享 Kind 和 Name
类型断言比 reflect 更快、更安全,优先使用
除非你写的是泛型容器、序列化库或调试工具,否则绝大多数业务逻辑中,用类型断言(v, ok := x.(T))比反射更直接、零开销、无 panic 风险。
立即学习“go语言免费学习笔记(深入)”;
- 反射无法绕过 Go 的导出规则:无法访问未导出字段,
.Field(0)对私有字段返回 zero Value - 反射性能差:每次
reflect.TypeOf()或reflect.ValueOf()都有内存分配和类型检查开销,基准测试中通常是类型断言的 10–100 倍 - 真正需要反射的典型场景:实现
json.Marshaler序列化任意结构体、编写 ORM 字段映射、构建通用 validator —— 这些场景里,类型不确定且需深度遍历字段
Type 还是 Value,实际是问“我到底要不要绕过类型系统”。大多数时候,你并不需要。










