如何让Go结构体omitempty仅在json.Unmarshal生效,Marshal时必输出字段
实现方案
你当前结构体的omitempty标签已经满足反序列化时a、c为可选字段的要求:JSON输入中缺失这两个字段时,反序列化会自动赋值为对应类型的零值,无需额外调整。仅需要针对序列化逻辑做自定义处理,即可实现两个字段强制输出的要求,推荐以下两种方案:
方案1:自定义MarshalJSON接口(最常用)
通过自定义序列化方法,仅修改序列化时的字段标签,不影响原有反序列化逻辑。
注意:Go标准库
json包只能访问公共字段,你原有结构体的小写字段需要调整为大写开头,修改后的结构体定义如下:
type MyStruct struct { A string `json:"a,omitempty"` B int `json:"b"` C float64 `json:"c,omitempty"` }
给MyStruct实现json.Marshaler接口:
func (s MyStruct) MarshalJSON() ([]byte, error) { // 定义别名继承原有结构体所有字段和逻辑 type MyStructAlias MyStruct // 临时结构体覆盖a、c字段的标签,去掉omitempty return json.Marshal(&struct { A string `json:"a"` C float64 `json:"c"` *MyStructAlias }{ A: s.A, C: s.C, MyStructAlias: (*MyStructAlias)(&s), }) }
效果验证
- 反序列化:直接调用
json.Unmarshal处理MyStruct类型即可,缺失a、c字段时自动填充零值,符合可选要求 - 序列化:自动调用自定义方法,a、c哪怕是零值也会正常输出,不会被省略
方案2:指针类型(适合需要区分「未传值」和「传零值」的场景)
如果业务逻辑需要判断用户是否主动传入了a、c字段,而非直接用零值,可以将字段定义为指针类型:
type MyStruct struct { A *string `json:"a,omitempty"` B int `json:"b"` C *float64 `json:"c,omitempty"` }
使用说明
- 反序列化时:如果JSON中没有对应字段,A、C的值为
nil,可以以此判断用户是否主动传值 - 序列化前:手动将
nil的指针字段赋值为对应类型零值的指针,即可保证字段不会被省略:
// 序列化前统一处理空指针 if data.A == nil { emptyStr := "" data.A = &emptyStr } if data.C == nil { zeroVal := 0.0 data.C = &zeroVal } json.Marshal(data)
内容的提问来源于stack exchange,提问作者tardushechka
相关产品推荐
相关产品推荐

