json.unmarshal不返回解析结果,只返回error;err == nil仅表示解析无错,数据写入传入的指针变量中,若传值非指针、字段未导出或标签不匹配,会导致静默失败而数据为空。

json.Unmarshal 不返回解析结果,只返回 error;传错指针、字段未导出、标签不匹配,都会导致“解析成功但数据为空”——这是最常被忽略的静默失败。
为什么 err == nil 却拿不到数据
因为 json.Unmarshal 的设计就是“写入式”:它把值直接填进你传入的变量里,不返回新对象。返回 nil 只代表“没出错”,不代表“有数据”。常见陷阱包括:
- 传了
p而不是&p→ 编译通过,但结构体字段全为零值(Go 值传递) - 结构体字段是小写开头(如
name string)→ 完全跳过,不报错也不赋值 - 写了
json:"user_id"标签,但字段名是UserID int→ 匹配不上,保持零值 - 调试时只打印
err,没检查p本身 → 其实已经填好了,只是你没看
实操建议:解析后立刻加一句 fmt.Printf("→ %+v", p),比盯 err 有用十倍。
结构体字段必须大写 + 正确用 json tag
Go 的 encoding/json 包只处理导出字段(首字母大写),且默认按字段名匹配 JSON key。但外部 API 几乎不用驼峰,所以光大写不够,必须靠 json:"xxx" 显式对齐。
-
User_id int `json:"user_id"`→ JSON 中是"user_id": 123才能写入 -
CreatedAt time.Time `json:"created_at"`→ 字段语义清晰,tag 控制序列化行为 -
Options *[]string `json:"options,omitempty"`→omitempty只影响json.Marshal,反序列化时缺失字段不修改原值 - 嵌套结构体同理:内层字段也得大写 + tag,漏一层就整个子结构为零值
遇到 null、缺失字段或类型不匹配怎么办
json.Unmarshal 的容错策略务实但容易埋坑:
- JSON 是
null,目标是*string→ 赋值为nil - JSON 是
null,目标是string→ 不修改原值(若未初始化就是空字符串) - JSON 字段缺失(如没有
"email")→ 对应字段保持原值,不会清空 - JSON 字符串塞进
int字段 → 直接返回json.UnmarshalTypeError,不是跳过
这意味着:想让某个字段“必须存在”,不能依赖 Unmarshal 自动校验,得自己加逻辑,比如 if p.Email == "" { return errors.New("email required") }。
别反复 Unmarshal 同一段 []byte
每次调用 json.Unmarshal(data, &v) 都会重新做词法分析和语法树构建,开销不小。尤其在 API 网关或高频解析场景下,重复解析同一段原始 JSON 很浪费。
- 先用
json.RawMessage接住不确定结构的子字段,延迟解析 - 或一次性解析成
map[string]interface{},再按需取值并手动转类型 - 注意:
json.RawMessage保存的是原始字节引用,如果原始[]byte被复用或释放,它会失效
真正难的不是写对第一行 json.Unmarshal,而是确保所有嵌套层级的字段都导出、都有 tag、都经得起 null 和缺失字段的考验——这些细节在日志里几乎不报错,只在业务逻辑跑偏时才暴露。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











