json.Unmarshal要求所有嵌套字段必须导出(首字母大写),否则静默失败、值为零值;匿名嵌入不自动映射嵌套JSON,需分层定义导出结构体并配json标签。

json.Unmarshal 要求所有嵌套字段都必须导出,否则静默失败 —— 这是绝大多数“解析后为空”的根本原因。
结构体字段首字母必须大写才能被 json.Unmarshal 访问
小写字母开头的字段(如 name string)对 encoding/json 完全不可见,反序列化时不会报错,但值永远是零值。
-
Name string `json:"name"`✅ 可导出、有 tag,能正确赋值 -
name string `json:"name"`❌ 即使有 tag,也不会被填充 - 嵌套结构体里的字段也必须全部导出,否则内层字段照样为零值
- 匿名嵌入(如
User struct{ ID int })不等于自动映射 JSON 字段;它要求 JSON 是扁平结构,而非{"user":{"id":1}}
嵌套层级别硬展开,用命名结构体分层建模
面对类似 {"response":{"data":{"list":[{"item":{"id":1}}]}}} 的四层 JSON,强行定义 Response.Data.List[0].Item.ID 对应的四级结构体,会导致类型爆炸、字段难维护。
- 推荐拆成
type Response struct { Data DataResp `json:"data"` }、type DataResp struct { List []ItemResp `json:"list"` }等独立类型 - 每层结构体只负责一层语义,复用性强,单元测试易写
- 避免在 struct 字段中直接使用
[]struct{...}匿名定义,IDE 无法跳转、字段不可导出、tag 易遗漏 - 中间容器字段(如
"payload"或"data")可保留为字段,不强制拆解,降低耦合
数组混型时用 json.RawMessage 延迟解析
当 JSON 数组元素类型不一致(如 [{"type":"user","name":"A"},{"type":"admin","level":9}]),直接解到统一 struct 会触发 json: cannot unmarshal object into Go struct field 错误。
- 声明字段为
Items []json.RawMessage `json:"items"`,不触发即时解析 -
json.RawMessage是[]byte别名,零拷贝,可多次用于json.Unmarshal - 遍历每个
json.RawMessage,先读取"type"字段,再按需解码到对应 struct - 不能把
json.RawMessage当作“可重读流”——它只是字节切片,没有内部状态,但重复Unmarshal是安全的
反射访问嵌套字段时必须逐层校验 IsValid() 和 CanInterface()
Go 反射不支持点号路径(如 v.FieldByName("User.Address.City")),直接链式调用 FieldByName 在某层失败时会返回零值,后续调用 Interface() 就 panic:reflect: call of reflect.Value.Interface on zero Value。
立即学习“go语言免费学习笔记(深入)”;
- 每层都要先判断
v.Kind() == reflect.Ptr并检查!v.IsNil(),再v.Elem() - 遇到
reflect.Interface类型,需先v.Elem()拿到底层值,再继续处理 - 每次
FieldByName后必须立即检查v.IsValid()和v.CanInterface() - 性能敏感场景下,避免在循环里反复调用
reflect.TypeOf和reflect.ValueOf—— 提前缓存Type和Value
Elem(),就足以让整个解析流程静默失效。


















