Golang使用JSON完成数据序列化与反序列化

14次阅读

json.Marshal返回空字符串或错误主因是结构体字段未导出(首字母小写),需大写字段名并用json:”key,omitempty”标签;NULL处理需用*String指针sql.NullString;json.RawMessage用于延迟解析;自定义time.Time类型实现MarshalJSON/UnmarshalJSON以支持ISO8601格式。

Golang使用JSON完成数据序列化与反序列化

为什么 json.Marshal 会返回空字符串或错误?

常见原因是结构体字段未导出(首字母小写),json 包无法访问私有字段,序列化结果为 {} 或跳过该字段。

  • 确保结构体字段首字母大写(如 Name 而非 name
  • 若需自定义 JSON 字段名,用结构体标签:json:"user_name,omitempty"
  • omitempty 表示值为零值(""0falsenil)时忽略该字段
  • 嵌套结构体中任一字段不可导出,整个嵌套对象可能为空(不是报错,而是静默丢弃)

如何处理 JSON 中的空字符串、null 和缺失字段?

gojson.Unmarshalnull 的处理取决于目标类型的可空性。原生类型(如 stringint)无法表示 null,反序列化时若遇到 null 会报错 json: cannot unmarshal null into Go value

  • 指针类型接收可选字段:*string*int —— null 会被转为 nil
  • sql.NullString 等标准空值包装器(需实现 UnmarshalJSON
  • 自定义类型可实现 UnmarshalJSON([]byte) Error 方法,统一处理 null / 空字符串 / 缺失
  • map 类型,null 会解为 nil;对 slice,同理

json.RawMessage 适合什么场景?

当你需要延迟解析某段 JSON(比如字段结构不确定、或想避免重复解析)、或透传未知结构(如 webhook payload 中的 data 字段),json.RawMessage 是最轻量的选择 —— 它只是字节切片的别名,不触发解析开销。

  • 声明字段类型为 json.RawMessage,反序列化时原样拷贝原始 JSON 字节
  • 后续按需调用 json.Unmarshal 解析它,支持多次解析不同结构
  • 注意:不能直接打印或比较 json.RawMessage 值,它是 []byte,需转 string 才可读
  • 若字段可能为 null,建议用 *json.RawMessage,否则 null 会导致解析失败
type Event struct {     ID     int              `json:"id"`     Type   string           `json:"type"`     Data   json.RawMessage  `json:"data"` }  var e Event json.Unmarshal([]byte(`{"id":1,"type":"user","data":{"name":"alice"}}`), &e) // 此时 e.Data == []byte(`{"name":"alice"}`)  var user struct{ Name string } json.Unmarshal(e.Data, &user) // 按需解析

时间字段序列化成 ISO8601 格式失败怎么办?

Go 默认将 time.Time 序列化为 Go 内部格式(类似 "2006-01-02T15:04:05.999999999Z07:00"),但多数 API 要求 ISO8601(如 "2024-05-20T08:30:00Z")。直接用 time.Time 无法控制格式。

立即学习go语言免费学习笔记(深入)”;

  • 定义自定义类型并实现 MarshalJSONUnmarshalJSON
  • MarshalJSON 中调用 t.format(time.RFC3339)
  • UnmarshalJSON 中用 time.Parse(time.RFC3339, s),注意处理带毫秒和不带毫秒的变体
  • 避免在结构体中混用原生 time.Time 和自定义时间类型,容易漏处理

字段级控制比全局设置更可靠,因为不同接口对时间精度要求可能不同。

text=ZqhQzanResources