Go jsonnull 怎么处理JSON 数组
来源:17golang原创
时间:2026-09-13 10:12:01 266浏览 收藏
Go 里处理 JSON 数组时,最容易踩坑的是把 null 和 [] 当成同一种“没有数据”。用标准库 encoding/json 解码到切片时,null 会得到 nil 切片,空数组会得到非 nil 但长度为 0 的切片;重新编码时,前者默认输出 null,后者输出 []。如果接口契约要求“数组字段永远是数组”,就要在输出边界主动归一化。
null与[]都能解码成功,但nil判断结果不同。- 普通结构体切片无法直接区分“字段缺失”和“字段为 null”,需要
RawMessage或指针。 omitempty会同时忽略nil切片和零长度切片,不能拿它表达三态业务语义。
先把 Go jsonnull 和空数组的差异看清
假设接口返回一个名为 items 的数组。最小实验不需要引入第三方包,直接让两个变量分别接收 null 与 []:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var fromNull []string
var fromEmpty []string
// null 表示没有切片值,[] 表示已经存在但没有元素的切片。
_ = json.Unmarshal([]byte(`null`), &fromNull)
_ = json.Unmarshal([]byte(`[]`), &fromEmpty)
// 用 nil 和 len 同时观察两种状态,避免只看元素数量。
fmt.Println(fromNull == nil, len(fromNull)) // true 0
fmt.Println(fromEmpty == nil, len(fromEmpty)) // false 0
// 重新编码时,两种状态会保留到 JSON 表示中。
nullJSON, _ := json.Marshal(fromNull)
emptyJSON, _ := json.Marshal(fromEmpty)
fmt.Println(string(nullJSON)) // null
fmt.Println(string(emptyJSON)) // []
}
这里的关键不是长度,而是 fromNull == nil。两者都能安全地进行 len、range 和追加,但它们表达的协议语义不同。标准库文档也明确说明,JSON null 解码到切片时会把 Go 值设为 nil;空数组则替换为一个新的空切片。

字段缺失、null 和 [] 为什么还不一样
把切片直接放进结构体时,字段缺失和显式 null 最后都可能留下 nil,因此普通写法只能解决“数组还是空数组”的一部分问题:
type Payload struct {
Items []string `json:"items"`
}
func decodePayload(data []byte) (Payload, error) {
var payload Payload
// 解码结果需要返回给调用方,不能只依赖后续 len 判断。
if err := json.Unmarshal(data, &payload); err != nil {
return Payload{}, err
}
return payload, nil
}
如果业务只关心“有没有可迭代的元素”,这样足够;如果要区分字段没传、传了 null、传了空数组,则可以先保留原始字段:
type RawPayload struct {
Items json.RawMessage `json:"items"`
}
func inspectItems(data []byte) (string, error) {
var payload RawPayload
// RawMessage 让字段存在性先被保留下来,再决定如何转换。
if err := json.Unmarshal(data, &payload); err != nil {
return "invalid-json", err
}
if payload.Items == nil {
return "missing", nil
}
if string(payload.Items) == "null" {
return "null", nil
}
var items []string
if err := json.Unmarshal(payload.Items, &items); err != nil {
return "invalid-items", err
}
if items == nil {
return "null", nil
}
return "array", nil
}
生产代码里不建议只用字符串比较来处理复杂 JSON;示例的目的只是突出三态判断。正式转换时可以把 RawMessage 交给第二次 json.Unmarshal,并把类型错误返回给上层,而不是静默把对象或字符串当数组。
回写接口时,先决定要输出 null 还是 []
很多“Go jsonnull”问题其实发生在响应编码阶段:数据库查询没有结果时切片保持 nil,json.Marshal 就会返回 null。若前端协议约定数组字段固定为数组,可以在组装响应时归一化:
type Response struct {
Items []string `json:"items"`
}
func normalizeItems(items []string) Response {
// 对外协议要求数组时,把 nil 转成非 nil 的空切片。
if items == nil {
items = make([]string, 0)
}
return Response{Items: items}
}
反过来,如果 null 有“尚未计算”“不适用”之类的业务含义,就不要无条件转成 []。这时应在领域模型中保留一个明确的存在状态,或使用指针/自定义类型,让响应层能表达这个含义。

omitempty 不是三态字段开关
json:"items,omitempty" 会在切片为 nil 或长度为 0 时省略字段。它适合“空集合不需要传输”的接口,但不适合同时表达“缺失、null、空数组”三种状态。
可以按下面的规则做选择:
| 输入或内部状态 | 默认解码结果 | 默认编码结果 | 适合场景 |
|---|---|---|---|
null | nil 切片 | null | 未提供、未知或不适用 |
[] | 非 nil 空切片 | [] | 明确表示集合为空 |
| 字段缺失 | 通常保持零值 | 按标签决定 | 兼容旧客户端或可选字段 |
最后检查四件事:解码后是否需要 nil 判断;接口是否允许 null;写响应前是否统一初始化空切片;omitempty 是否会误删字段。只要这四个问题先定下来,Go 对 JSON 数组的处理就不会被“长度都是 0”带偏。
相关问题
Go 的 nil 切片能直接 range 吗?
可以。对 nil 切片使用 range、len 和 append 都是安全的,但编码结果仍可能与空切片不同。
为什么接口返回的数组偶尔变成 null?
常见原因是响应模型中的切片从未初始化,仍是 nil;在编码前把它归一化为空切片,或按协议保留 null 的业务含义即可。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
242 收藏
-
204 收藏
-
287 收藏
-
Golang · Go问答 | 1小时前 | 连接池 · HTTP客户端 · Go问答 · Transport · 生命周期管理 · Go HTTP客户端 连接池 http.Transport CloseIdleConnections Transport生命周期262 收藏
-
Golang · Go问答 | 1小时前 | 连接池 · HTTP客户端 · Go问答 · 端口排查 · Transport · TIME_WAIT httptrace http.Transport Go transport Go端口增长 HTTP连接复用 CLOSE_WAIT297 收藏
-
Golang · Go问答 | 1小时前 | 性能排查 · HTTP客户端 · Go问答 · 连接复用 · Transport · MaxIdleConnsPerHost Go连接池 Go transport http.Transport连接复用 HTTP keep-alive268 收藏
-
Golang · Go问答 | 1小时前 | Context · HTTP客户端 · Go问答 · Transport · 请求超时 · Go请求超时 Go clienttimeout http.Client Timeout Go客户端超时 Transport阶段超时338 收藏
-
465 收藏
-
Golang · Go问答 | 2小时前 | 错误处理 · net/http · HTTP客户端 · Go问答 · 请求超时 · Go clienttimeout http.Client Timeout Go 请求超时 Go url.Error 超时 Go HTTP 客户端时限351 收藏
-
292 收藏
-
327 收藏
-
377 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习