json:"-" 表示完全忽略字段,序列化时不输出、反序列化时不解析;若需仅跳过序列化而保留反序列化,应使用 json:",omitempty" 配合零值控制或私有字段加自定义 MarshalJSON。

用 json:"-" 就能跳过字段序列化,但得注意它只影响 json.Marshal,对 json.Unmarshal 也生效——也就是说,反序列化时这个字段永远收不到值。
为什么 json:"-" 会同时跳过序列化和反序列化
Go 的 encoding/json 包把 - 当作“完全忽略该字段”的指令,不是“只读”或“只写”。它不生成 JSON 键,也不尝试从输入 JSON 中匹配该字段名。
- 如果你只想跳过序列化(输出),但还想在反序列化(输入)时接收值,
json:"-"不适用 - 常见误用场景:给
ID或CreatedAt加json:"-",结果 API 接收 JSON 创建对象时,这些字段始终为零值 - 真正需要“只读不写”的字段,得靠自定义
MarshalJSON方法,而不是 tag
想跳过序列化但保留反序列化?用 json:"name,omitempty" + 零值控制
这不是万能解法,但最常用。核心思路是:让字段在序列化时“消失”,仅当它有非零值才出现;而反序列化照常工作。
-
omitempty只在字段值为对应类型的零值(0、""、nil、false)时跳过该字段 - 适用于你希望字段默认不输出,但允许客户端传入并被正确解析的场景
- 注意:指针类型要小心,
*string的零值是nil,omitempty会跳过;但一旦解出非 nil 值,下次序列化又可能因内容为空字符串而被跳过
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Password *string `json:"password,omitempty"` // 密码不输出,但可接收
}
需要彻底隐藏敏感字段(如密码)且禁止反序列化?用私有字段 + 自定义方法
如果字段绝对不能出现在 JSON 输入/输出中(比如数据库密码、临时 token),别依赖 struct tag,改用私有字段 + 手动控制。
立即学习“go语言免费学习笔记(深入)”;
- 将字段改为小写开头(如
password),它天然不会被json包导出 - 配合
MarshalJSON实现按需过滤(比如只在调试时输出) - 避免用
json:"-"去“掩耳盗铃”地藏敏感字段——只要字段是公开的,反射就能读到,json:"-"没有安全意义
type User struct {
ID int `json:"id"`
Name string `json:"name"`
password string `json:"-"` // 私有字段,加不加 "-" 都不会被序列化
}
func (u User) MarshalJSON() ([]byte, error) {
type Alias User // 防止无限递归
return json.Marshal(&struct {
*Alias
// 不嵌入 password 字段
}{
Alias: (*Alias)(&u),
})
}
最容易被忽略的是:字段是否公开(首字母大小写)比 tag 更底层。哪怕写了 json:"-",只要字段是大写的,它就仍可能被其他包通过反射访问到——这在做权限校验或审计日志时很关键。


















