在 Go 的 encoding/json 包中,json.RawMessage 是一个很实用的类型。它本质上是 []byte,用于保存一段未经解析的 JSON 数据,让程序可以延迟决定如何解析。
例如接口返回的数据中,data 字段可能对应不同结构:
type Response struct {
Code int `json:"code"`
Data json.RawMessage `json:"data"`
}
第一次 json.Unmarshal 时,Data 不会被解析成 map[string]any,而是直接保存原始 JSON。根据 Code 或其他字段确定具体类型后,再进行第二次解析:
var user User
if err := json.Unmarshal(resp.Data, &user); err != nil {
return err
}
这种方式特别适合多态 JSON、动态字段、消息路由和兼容不同版本的数据结构。
与 any 的区别
如果使用 any 接收 JSON,就相当于把内容当作 map[string]any 解析,其中数字解析为 float64,导致类型信息丢失。
json.RawMessage 则保留 JSON 原文,可以在真正需要时再决定目标类型,也避免了不必要的解析。
type Response struct {
Type string `json:"type"`
Data any `json:"data"`
}
{
"type": "user",
"data": {
"id": 123,
"name": "Woody"
}
}
// map[string]any{
// "id": float64(123),
// "name": "Woody",
// }