json.marshal仅在类型直接实现json.marshaler或json.unmarshaler接口时调用对应方法;若指针接收器实现但传入值类型,或字段含未导出/不支持类型,将导致方法不调用或报错。

为什么 json.Marshal 不调用你的方法?
因为 Go 的 JSON 序列化只认两个接口:json.Marshaler 和 json.Unmarshaler,且仅当类型**直接实现**这两个接口时才生效。常见错误是给指针类型实现了接口,但值类型变量被传入 json.Marshal —— 这时不会触发方法调用。
比如你写了 func (t *MyType) MarshalJSON() ([]byte, error),但传的是 MyType{}(非指针),那 MarshalJSON 就不会执行。
- 检查接收器类型:值接收器对应值变量,指针接收器对应指针变量或取地址后的值
- 确认变量实际类型:用
fmt.Printf("%T", v)看传入的是MyType还是*MyType - 如果结构体字段是值类型,嵌入时也需保持接收器一致性,否则嵌套序列化会跳过自定义逻辑
如何让时间字段输出为 "2006-01-02" 而不是 RFC3339?
标准 time.Time 的 MarshalJSON 输出带时区和纳秒的完整字符串,但业务常要简化格式。不能直接改 time.Time(不可修改标准库类型),得包装一层。
推荐做法:定义新类型并实现 json.Marshaler:
type Date time.Time
func (d Date) MarshalJSON() ([]byte, error) {
return []byte(`"` + time.Time(d).Format("2006-01-02") + `"`), nil
}
// 用法:struct 中字段类型声明为 Date,不是 time.Time
type Event struct {
When Date `json:"when"`
}
- 注意返回字节必须包含双引号,
json.Marshal不会自动加 - 别漏掉
time.Time(d)类型转换,否则Format方法不可用 - 如果还要反序列化,必须同时实现
UnmarshalJSON,且处理带引号的字符串输入
嵌套结构体里部分字段想忽略,但又不想用 json:"-" ?
全局忽略用 tag 最简单,但有时逻辑更复杂:比如仅在特定状态(如 Status == "draft")下才忽略某个字段。这时得靠自定义 MarshalJSON 手动控制字段输出。
核心思路:手动构造 map,按条件决定是否加入键值对,再用 json.Marshal 编码该 map:
func (u User) MarshalJSON() ([]byte, error) {
type Alias User // 防止无限递归
raw := struct {
*Alias
CreatedAt string `json:"created_at,omitempty"`
}{
Alias: (*Alias)(&u),
}
if u.Status != "draft" {
raw.CreatedAt = u.CreatedAt.Format(time.RFC3339)
}
return json.Marshal(raw)
}
- 用
type Alias User是关键,避免调用自身MarshalJSON导致死循环 - 字段名大小写必须和目标 JSON key 一致,否则字段不出现
- 不要试图在
MarshalJSON里直接拼接 JSON 字符串,易出错且难维护;优先走 map 或匿名 struct 路线
为什么实现了 MarshalJSON 却仍报 json: unsupported type?
这个错误通常不是因为你没实现接口,而是底层字段类型不被 json.Marshal 支持 —— 比如字段是 func、chan、map[interface{}]interface{} 或未导出字段(小写开头)。
- 检查结构体中所有字段是否可导出(首字母大写),否则即使实现了接口,内部字段也无法被反射访问
- 确认没有嵌入不支持的类型:例如
http.Handler、sync.Mutex等,它们本身不可序列化 - 如果用了
map[string]interface{}存动态数据,确保值类型都在 JSON 支持范围内(string/int/float/bool/map/slice/nil) - 第三方类型(如
uuid.UUID)需自行实现MarshalJSON,或用其自带的序列化方法转成字符串再存
最稳妥的做法:在自定义 MarshalJSON 中显式列出要序列化的字段,不依赖反射自动遍历。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











