
用 reflect.TypeOf 看变量底层类型,但别直接打印结果
它返回的是 reflect.Type 类型,不是字符串。直接 fmt.Println(reflect.TypeOf(x)) 虽能输出名字,但容易误判——比如 type MyInt int 和 int 打印出来都像 int,实际类型不同。
正确做法是调用 .Name() 或 .String() 方法:
package main
import (
"fmt"
"reflect"
)
type MyInt int
func main() {
var x MyInt = 42
fmt.Println(reflect.TypeOf(x).Name()) // 输出 "MyInt"
fmt.Println(reflect.TypeOf(x).String()) // 输出 "main.MyInt"
}
-
.Name()只返回类型名(无包路径),对内建类型如int、string返回空字符串 -
.String()返回完整限定名(含包路径),更可靠,尤其跨包时 - 接口变量传进去会得到接口类型本身,不是底层值的类型——要先
reflect.ValueOf(x).Elem()再取类型
指针、切片、map 这类复合类型,reflect.TypeOf 返回的是“描述结构”的类型对象
它不展开嵌套,只告诉你这个变量当前是什么类型。比如 *[]string,reflect.TypeOf 返回的是指向切片的指针类型,不是 []string 本身。
- 用
.Kind()判断基础分类:reflect.Ptr、reflect.Slice、reflect.Map等,比.Name()更稳定 - 想拿到指针指向的类型?链式调用
.Elem():reflect.TypeOf(&x).Elem().Name() - 切片元素类型是
[]T的T,得用.Elem();map 的 key/value 类型要用.Key()和.Elem()
不能对 nil 接口或未初始化的 interface{} 调用 reflect.TypeOf
如果传入一个零值的 interface{}(比如声明了没赋值),reflect.TypeOf 返回 nil,后续调用方法会 panic。
立即学习“go语言免费学习笔记(深入)”;
- 安全写法是先判断:
if t := reflect.TypeOf(x); t != nil { ... } - 更常见的情况是函数参数为
interface{},但传了nil:此时reflect.TypeOf拿不到任何类型信息,只能靠文档或额外参数约定 - struct 字段为 nil 指针时,
reflect.TypeOf仍能正常工作——它看的是字段声明类型,不是字段值
性能敏感场景下,避免在热路径反复调用 reflect.TypeOf
反射开销不小,尤其是类型检查逻辑被编译器优化掉之后,reflect.TypeOf 是运行时行为。高频调用(比如网络包解析循环里)会明显拖慢速度。
- 类型已知时,优先用类型断言:
v, ok := x.(string),比反射快一个数量级 - 必须用反射时,把
reflect.TypeOf结果缓存起来,比如定义为包级变量或通过sync.Once初始化 - 生成代码(如
go:generate+stringer)比运行时反射更适合固定类型的场景
真正难的不是怎么调用 reflect.TypeOf,而是搞清你到底需要“类型名”“底层类型”还是“运行时动态类型”——这三个在 Go 里经常不是一回事。










