go的json.marshal仅序列化首字母大写的导出字段,小写字段被静默忽略;需用struct tag自定义键名、omitempty省略零值,time.time等特殊类型需额外处理。

Go 的 json.Marshal 能直接把结构体转成 JSON 字符串,但默认行为常让人踩坑——比如字段名全小写、空字段不忽略、时间变成数字戳。
结构体字段必须是导出的(首字母大写)
Go 的 json 包只能序列化导出字段。如果字段名是 name 或 id 这种小写开头,json.Marshal 会直接忽略它,结果里啥都没有。
解决办法很简单:确保字段首字母大写,并用 json tag 显式声明键名:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
注意:`json:"name"` 中的反引号不能漏,否则编译报错;tag 值里不要加空格,比如 `json:"name "` 会导致键名带空格。
处理零值字段(omitempty)
空字符串 ""、零值 0、false、nil 指针或 slice 默认仍会出现在 JSON 中。多数 API 不想要这些冗余字段。
加 omitempty 就能跳过零值:
type Config struct {
Timeout int `json:"timeout,omitempty"`
Host string `json:"host,omitempty"`
Debug bool `json:"debug,omitempty"`
}
但要注意:omitempty 对指针、接口、map、slice、数组生效,对普通 struct 字段只判断其内部是否全为零值(不是“是否为 nil”);另外,它不会跳过显式赋值为零值的字段,比如 Timeout: 0 仍会被序列化——除非你用指针类型 *int 并设为 nil。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
时间字段默认序列化成 Unix 时间戳
如果结构体里有 time.Time 字段,json.Marshal 默认输出的是秒级时间戳(float64),不是 ISO8601 字符串,前端很难读。
正确做法是自定义类型并实现 MarshalJSON 方法:
type ISOTime time.Time
func (t ISOTime) MarshalJSON() ([]byte, error) {
return []byte(`"` + time.Time(t).Format(time.RFC3339) + `"`), nil
}
type Event struct {
CreatedAt ISOTime `json:"created_at"`
}
别直接在原生 time.Time 上加 tag(如 json:"created_at,string")——那只会让时间变成带引号的数字字符串,比如 "1712345678",不是你想要的 "2024-04-05T12:34:56Z"。
嵌套结构体与 nil 指针安全
结构体字段是指针类型时,比如 *Address,如果该指针是 nil,json.Marshal 会输出 null;但如果没加 omitempty,它仍会出现在 JSON 里。
常见陷阱:
- 忘记初始化嵌套结构体指针,导致意外
null - 用
omitempty后,nil指针被忽略,但非nil却全零值的结构体仍会输出(因为omitempty对 struct 本身不生效) - 想统一控制嵌套字段是否出现,得在嵌套类型内部也加
omitempty,而不是只在外层加
更稳妥的做法是:对可能为 nil 的嵌套字段,用指针类型 + omitempty;对一定存在的,用值类型并确保字段都带 omitempty。
真正麻烦的不是怎么调 json.Marshal,而是字段 tag 写错、时间格式不对、指针和零值混用导致前后端解析失败——这些问题在线上才暴露,本地测不出。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










