非用 reflect 不可的场景是面对未知类型时,如 json.Unmarshal 解析任意结构体、ORM 遍历字段、Excel 导出自动取字段名、通用校验库读取 tag 等,硬编码无法扩展。

什么时候非用 reflect 不可?
当你写的代码要“面对未知类型”运行时,reflect 就不是可选项,而是唯一解。比如:json.Unmarshal 为什么能解析任意结构体?它不知道你传的是 User 还是 Order,但必须把字段名、类型、嵌套关系全对上——这只能靠反射动态查。同理,ORM 插入数据前得遍历结构体字段,匹配数据库列;导出 Excel 时得自动读出所有公开字段名当表头;写通用校验库时得根据 json tag 或自定义 tag 决定是否忽略某字段……这些场景下,硬编码 switch 或一堆 if v, ok := obj.(TypeX) 会迅速失控。
reflect.TypeOf 和 reflect.ValueOf 怎么用才不踩坑?
最常见错误是传值而非指针导致无法修改、或忽略 CanSet() 直接调用 SetXxx() 导致 panic。关键规则只有两条:
- 想读字段值?
reflect.ValueOf(obj).Field(i).Interface()可行,但字段必须首字母大写(导出) - 想改字段值?必须传指针:
v := reflect.ValueOf(&obj).Elem(),再检查v.Field(i).CanSet()才能调SetString()等 - 访问结构体 tag?用
t.Field(i).Tag.Get("json"),不是t.Field(i).Tag直接取字符串——后者包含所有键值对,需解析
哪些场景看似能用反射,其实该用更简单的方式?
反射不是银弹,多数日常逻辑完全不需要它:
- 已知类型之间的转换?优先用类型断言:
if s, ok := v.(string),比reflect.TypeOf(v).Kind() == reflect.String更快、更安全 - 只做一次的结构体比较?
==或reflect.DeepEqual都可以,但后者开销大,且会穿透私有字段——如果本意是“语义相等”,应实现Equal()方法 - 需要调用固定几个方法?用接口抽象,而不是用
v.MethodByName("Save").Call()—— 后者丢失编译期检查,出错在运行时
性能敏感时怎么缓存反射结果?
反复调 reflect.TypeOf(obj) 或遍历字段是典型性能黑洞。真实项目中(如 GORM、ent),都会把 reflect.Type 和字段信息预计算并缓存:
- 用
sync.Map或全局 map 缓存reflect.Type→ 字段索引映射 - 字段遍历结果(如
[]reflect.StructField)只算一次,后续直接查表 - 基准测试务必用
b.ResetTimer()排除初始化开销,否则测出来的是缓存未命中时的毛刺值
真正难的从来不是“怎么用反射”,而是判断“这里到底该不该用”——一旦开始为一个字段加 interface{} 参数,就得立刻问自己:这个函数未来会不会被 20 种结构体调用?有没有更静态、更易测试的替代路径?










