背景
JSON
是一种轻量级的数据交换格式,Go 语言的 encoding/json
包自诞生以来已有十年之久,它凭借其灵活的特性赢得了开发者的青睐。开发者可以通过结构体标签自定义字段的 JSON 表现形式,也可以让 Go 类型自定义其在 JSON 中的表现形式。然而,随着 Go 语言和 JSON 标准的发展,一些功能上的缺失和性能上的限制逐渐暴露出来。
- 功能缺失:比如,不能指定
time.Time
类型的自定义格式化,不能在序列化时省略特定的 Go 值等。 - API 缺陷:比如,没有简单的方法来正确地从
io.Reader
中反序列化 JSON。 - 性能限制:标准
json
包的性能表现并不尽如人意,特别是在处理大量数据时。 - 行为缺陷:比如,对 JSON 语法的错误处理不够严格,大小写不敏感的反序列化等。
就像math/v2
一样的,Go 官方提出encoding/json/v2
来解决上面的那些问题,本文主要目标是分析enable/json中 关于空值的一些问题。以及它在 encoding/json/v2
中是如何被解决的。本文不涉及 encoding/json/v2
中其他的修改
This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on Medium. Thank you very much.
omitempty
在encoding/json
包中,有这样关于omitempty
的描述:
The “omitempty” option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
但是,这种预定义的”空”值判断逻辑并不能满足所有实际场景的需求。我们来看一个例子:
|
|
输出结果为:
|
|
虽然Post
各个字段都添加了omitempty
。但是结果并不像我们预期一样。
omitempty
不能处理空struct
,比如Post.Category
omitempty
处理time.Time
的方式不是 我们理解的UTC =0
,也就是1970-01-01 00:00:00
,而是0001-01-01T00:00:00Z
。
omitzero标签
在 encoding/json/v2
中,会添加一个新的标签 omitzero
,添加了两个功能,来解决上面的两个问题。(目前这个功能还在开发中,不过可以通过go-json-experiment/json提前体验新功能)
- 更好的
time.Time
处理。 - 支持自定义
IsZero
函数。
比如下面下面的代码:
|
|
跟encoding/json
相比 encoding/json/v2
解决了上面提到的问题。
|
|
结论
通过引入omitzero
标签,Go语言在解决JSON编码中”空”值处理的痛点上迈出了重要一步。这个方案不仅满足了开发者对更灵活的”空”值定义的需求,还保持了与现有系统的兼容性。目前该omitzero
的落地时间尚未确定,最早也要等到Go 1.24
版本。此外,encoding/xml等也会效仿json包,增加omitzero
标签。
encoding/json/v2
还包括 性能等其他方面的更新, 有兴趣的Gopher 可以 提前了解这些改动,本博客也会一直关注这个proposal
Go语言开始走向成熟。