json.unmarshal不返回解析结果,只将数据写入传入的指针变量;返回nil仅表示写入成功,常见失败原因包括传值而非地址、结构体字段未导出(小写)、缺失json tag或类型不匹配。

json.Unmarshal 不返回数据,只写入你传的指针变量;解析失败不报 panic,但静默跳过字段或保留原值——这是绝大多数解析“没效果”的根源。
为什么 json.Unmarshal 返回 nil 却没拿到数据
因为 json.Unmarshal 的设计就是“写入式”:它只负责把 JSON 字节填进你给的地址,返回值 error 仅表示“写入是否成功”,不是解析结果本身。
- 传了
p而不是&p→ 编译通过,但结构体字段全为零值(Go 值传递) - 结构体字段小写开头(如
name string)→ 完全忽略,不报错也不赋值 - 打印
err == nil就结束,没看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只影响序列化,反序列化时该字段缺失就保持原值 - 嵌套结构体同理:内层字段也得大写 + tag,漏一层就整个子结构为零值
遇到 null、缺失字段或类型不匹配怎么处理
json.Unmarshal 的容错策略很务实,但也容易埋坑:
- JSON 是
null,目标字段是*string→ 赋值为nil(合理) - JSON 是
null,目标字段是string→ 不修改原值(若未初始化就是空字符串) - JSON 字段缺失(如没有
"email")→ 对应字段保持原值,不会清空 - JSON 字符串塞进
int字段 → 直接返回json.UnmarshalTypeError,不是跳过 - 想让某个字段“必须存在”?得自己加逻辑,比如
if p.Email == "" { return errors.New("email required") }
解析动态结构或高频场景下的替代方案
硬套结构体不现实时,别强撑;反复解析同一段 []byte 很浪费。
- 字段类型不确定(如
"data"可能是对象、数组、字符串甚至null)→ 用json.RawMessage接住,后续按需解析:Data json.RawMessage `json:"data"` - 不想定义结构体,只想快速取值 → 用
github.com/tidwall/gjson,支持路径表达式:gjson.Get(json, "user.name").String() - 大文件或流式响应 → 用
json.NewDecoder替代json.Unmarshal,避免一次性加载全部字节 -
json.RawMessage保存的是原始字节引用,如果原始[]byte被复用或释放,它会失效
最常被忽略的其实是“字段未导出”和“传值而非传址”这两个点——它们不会报错,只会让解析看起来像没发生。调试时第一反应不该是换库,而是先确认 &p 和字段首字母大写。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











