reflect.New 用于创建自定义类型零值指针,需传入 reflect.Type(如 reflect.TypeOf(MyStruct{}).Type),返回可寻址、可修改的 reflect.Value;reflect.StructOf 动态构造结构体时字段名须大写且符合标识符规则,生成类型无方法集、不可断言为预定义类型。

用 reflect.New 创建自定义类型的零值实例
创建自定义类型(比如结构体)的实例,最直接的方式不是调用 new() 或字面量,而是用 reflect.New —— 它返回一个指向新分配零值的指针 reflect.Value。注意:它不接受具体值,只接受 reflect.Type。
常见错误是传入指针类型本身(如 *MyStruct),结果得到 **MyStruct;正确做法是传入 reflect.TypeOf(MyStruct{}).Type 或 reflect.TypeOf((*MyStruct)(nil)).Elem()。
- 若已有变量:
v := reflect.ValueOf(&MyStruct{}).Elem()也能拿到可寻址的Value,但不如reflect.New(t).Elem()清晰 - 若类型来自接口或运行时未知,先用
reflect.TypeOf(x).Elem()提取底层类型(前提是x是指针) -
reflect.New(t)分配的内存可被Set*方法修改,而reflect.Zero(t)返回不可寻址的只读值
用 reflect.StructOf 动态构造结构体类型
当结构体字段名、数量、类型需在运行时决定(比如 ORM 映射、配置解析),reflect.StructOf 是唯一选择。它接收 []reflect.StructField,每个字段必须含 Name、Type,且 Name 首字母大写才可导出(否则后续无法赋值或导出)。
容易踩的坑:字段 Type 必须是有效 reflect.Type,不能是 nil;Tag 字符串若格式错误(如未闭合反引号),reflect.StructOf 会 panic,不是返回 error。
立即学习“go语言免费学习笔记(深入)”;
- 字段名必须符合 Go 标识符规则,且首字母大写才能被反射写入
- 想模拟匿名字段?不行 ——
reflect.StructField.Anonymous在StructOf中被忽略,动态结构体不支持嵌入 - 生成的类型每次调用都不同(
==比较为 false),不能和预定义类型混用,比如不能直接断言为MyStruct
给反射创建的结构体字段赋值
用 reflect.New 或 reflect.StructOf 创建的结构体实例,字段默认为零值;要设值,必须确保 reflect.Value 可寻址(CanAddr() 返回 true)且可设置(CanSet() 返回 true)。常见失败原因是忘了调用 .Elem() —— reflect.New(t) 返回的是指针的 Value,得先解引用。
- 对结构体字段赋值:先
v.FieldByName("Name").Set(x),其中x必须是同类型reflect.Value(如reflect.ValueOf("hello")) - 字符串、整数等基础类型直接用
SetString/SetInt更安全,避免类型不匹配 panic - 如果字段是未导出(小写开头),
CanSet()返回 false,反射无法修改 —— 这是 Go 的安全限制,无法绕过
反射创建类型后如何转回真实 Go 值
reflect.Value.Interface() 是唯一标准方式,但它有严格前提:该 Value 必须是可导出的(字段名大写)、且底层类型在编译期已知(即不是 StructOf 动态生成的类型)。对于动态结构体,Interface() 返回的是 interface{},无法直接类型断言成预定义 struct。
这意味着:动态构造的结构体基本只能继续用反射操作,或者用 map[string]interface{} 做中间层转换。强行用 unsafe 或 go:linkname 绕过,属于未定义行为,生产环境禁用。
- 若只是临时填充并序列化(如转 JSON),可直接传给
json.Marshal(v.Interface()),只要字段可导出即可 - 想和已有函数对接?最好一开始就设计成接收
interface{}+ 类型检查,而不是依赖反射后“变回原类型” -
reflect.StructOf生成的类型无法注册到json或gob的类型系统中,序列化时字段名全靠Tag控制,无 Tag 则用字段名本身
StructOf 产生的是未命名类型。










