必须实现 marshaljson 方法当默认序列化不满足业务需求时,如字段脱敏、时间格式定制、net.ip 转字符串、嵌套扁平化或不支持类型编码。

什么时候必须实现 MarshalJSON 方法
不是所有结构体都需要自定义序列化,只有当默认行为不符合业务需求时才必须动手。典型场景包括:
• 字段需脱敏(如 Password 输出为 "***")
• 时间字段要固定格式(如 "2006-01-02" 而非 RFC3339)
• net.IP 类型必须转成点分十进制字符串,否则会输出 [127,0,0,1]
• 嵌套结构需扁平化(如把 User.Address.City 直接提为 "city" 字段)
• 字段类型本身不支持 JSON 编码(func、map[interface{}]interface{}、未导出字段参与编码等)
MarshalJSON 方法签名和接收者陷阱
方法签名必须严格是 func (t *T) MarshalJSON() ([]byte, error),且务必用指针接收者。
常见错误是用了值接收者,结果 json.Marshal(u)(传值)完全不调用该方法——反射找不到匹配的导出方法。
返回的 []byte 必须是合法 JSON 片段,不能只写 {"name":"x"};缺少外层引号或括号会导致 invalid character 错误。
不要在方法里直接调用 json.Marshal(*t),否则触发无限递归 panic。
正确做法是绕过自定义逻辑,用类型别名隔离方法集:
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
func (u *User) MarshalJSON() ([]byte, error) {
type Alias User
return json.Marshal(&struct {
*Alias
Password string `json:"password"`
}{
Alias: (*Alias)(u),
Password: "***",
})
}
JSON 与 gob 的选型关键点
选 encoding/json 还是 encoding/gob,取决于使用场景:
• 对外 API 或跨语言交互 → 必须用 json,它是文本协议,可读、可调试、通用
• 内部服务间或 Redis 存储 → gob + base64 更高效,原生支持 interface{}、nil map/slice、函数类型(虽不序列化,但不 panic)
• gob 需提前 gob.Register(),尤其对 map[string]interface{} 等动态类型
• json 无法处理未导出字段,gob 可以(只要字段可访问)
容易被忽略的零值与标签细节
结构体字段必须首字母大写才能被 json 或 gob 访问,小写字段直接消失。json:"name,omitempty" 中的逗号不能漏,写成 json:"name omitempty" 会导致整个标签失效。omitempty 对空 slice、nil map、0、""、false 都生效,但有时你需要零值也保留(比如前端依赖字段存在性判断),那就别加它。
反序列化时,json.Unmarshal 不会调用你写的 MarshalJSON,它走默认逻辑;若需定制反解,必须同时实现 UnmarshalJSON。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










