reflect.new仅支持可寻址类型,传入接口/函数等会panic;reflect.makemap要求类型为map且key可比较,返回nil map而非空map,需用makemapwithsize(0)获取空map。

reflect.New 创建指针实例时,类型必须是可寻址的
用 reflect.New 得到的是一个 *T 类型的 reflect.Value,它背后对应一块新分配的内存。但如果你传入的是接口类型、函数类型、或未导出字段组成的 struct,运行时会 panic:panic: reflect: New(nil) 或 reflect: call of reflect.Value.Type on zero Value。
常见错误场景:把 interface{} 直接丢给 reflect.New,或者对 reflect.Value.Kind() == reflect.Interface 的值误调 New。
- 只对
reflect.Kind()是Struct、Int、String等非引用类型(且非 interface/func/map/slice/chan)才安全调用reflect.New - 若已有
reflect.Value,先用.Type()拿到reflect.Type,再传给reflect.New;别传.Interface()结果 - 想从接口变量反推具体类型再新建?得先
value.Elem()或value.Convert()到具体类型,否则reflect.New(value.Type())会失败
reflect.MakeMap 要求类型是 map,且 key 类型必须可比较
reflect.MakeMap 不接受任意 reflect.Type,只认 Kind() == reflect.Map 的类型。传入 struct、slice 或 interface{} 都会 panic:reflect: call of reflect.MakeMap on struct Type。
更隐蔽的坑是 key 类型:Go 规定 map 的 key 必须支持 == 比较,所以 reflect.MakeMap(reflect.MapOf(reflect.TypeOf([]int{}).Type(), reflect.TypeOf(0).Type())) 会 panic —— 因为 slice 不可比较。
立即学习“go语言免费学习笔记(深入)”;
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
- 构造 map 类型必须用
reflect.MapOf(keyType, elemType),不能靠reflect.TypeOf(make(map[string]int))反推后直接传给MakeMap(虽然可行,但不灵活) - key 类型推荐用
string、int、int64、uintptr或带导出字段的 struct;避开[]byte、func()、map[...]、含 unexported 字段的 struct -
reflect.MakeMap返回的是reflect.Value,不是底层 map;要赋值必须用.SetMapIndex(key, value),不能直接map[key] = val
反射创建的实例,零值行为和原生 new/make 不完全一致
reflect.New(T) 分配的内存内容是全零,和 new(T) 一致;但 reflect.MakeMap 返回的 map 是 nil map,不是空 map —— 这点和 make(map[K]V) 不同。直接对它 len() 没问题,但 range 或 delete() 会 panic。
典型现象:用 reflect.MakeMap 初始化后没做任何 SetMapIndex,就传给某个期望接收非-nil map 的函数,结果 runtime error:assignment to entry in nil map。
- 需要空 map 行为?得用
reflect.MakeMapWithSize(t, 0),它返回的是真实空 map(非 nil) - 不确定是否 nil?检查
v.IsNil(),而不是v.Len() == 0 - struct 字段含 map 类型?
reflect.New(T).Elem().FieldByName("M").Set(reflect.MakeMap(...))才能真正初始化该字段,否则仍是 nil
性能与逃逸:反射创建实例会绕过编译期优化
每次调用 reflect.New 或 reflect.MakeMap 都触发堆上分配,且无法被内联或逃逸分析优化。在高频路径里反复调用,GC 压力明显上升,实测比原生 new(T) 慢 5–10 倍以上。
这不是“能不能用”的问题,而是“值不值得用”。比如 ORM 字段映射、通用 JSON 解析器这类基础设施可以接受;但 HTTP handler 里为每个请求反射 new 一个 struct 就很危险。
- 如果类型集合固定,提前用
sync.Pool缓存reflect.Value实例,避免重复 New/Make - 避免在循环里反复调
reflect.TypeOf(x),它比reflect.ValueOf(x).Type()更重;缓存好reflect.Type复用 - 生成代码(如 go:generate)比运行时反射更稳——只要类型在编译期可知,优先考虑 codegen
reflect.MakeMap 默认给的是前者。









