嵌套结构体的MarshalJSON序列化不符合预期问题排查
解决方案:嵌套结构体序列化丢失字段+UTC时间处理问题
问题根源
你遇到的核心问题是:当匿名嵌入的结构体实现了json.Marshaler接口时,外层结构体将自动继承该接口实现。你的Contact结构体自定义了MarshalJSON来处理UTC时间,导致嵌套它的ContactWithIntro在序列化时,直接调用了继承来的Contact.MarshalJSON,完全忽略了外层的Intro字段。
方案1:给ContactWithIntro实现专属序列化方法
手动组合嵌套结构体的序列化结果与外层字段,既复用Contact的UTC时间逻辑,又保留Intro字段:
func (cwi ContactWithIntro) MarshalJSON() ([]byte, error) { // 先序列化Contact部分,复用已有的UTC转换逻辑 contactData, err := json.Marshal(cwi.Contact) if err != nil { return nil, err } // 将Contact的JSON转为map,添加Intro字段 var tempMap map[string]interface{} if err := json.Unmarshal(contactData, &tempMap); err != nil { return nil, err } tempMap["intro"] = cwi.Intro // 序列化最终的组合数据 return json.Marshal(tempMap) }
方案2:高效JSON拼接(性能优化版)
如果对序列化性能有要求,可以直接拼接JSON字节,避免转map的开销:
func (cwi ContactWithIntro) MarshalJSON() ([]byte, error) { // 序列化Contact部分 contactBytes, err := json.Marshal(cwi.Contact) if err != nil { return nil, err } // 序列化Intro字段 introBytes, err := json.Marshal(map[string]string{"intro": cwi.Intro}) if err != nil { return nil, err } // 拼接两个JSON对象(去掉首尾{}后用逗号连接) contactContent := contactBytes[1 : len(contactBytes)-1] introContent := introBytes[1 : len(introBytes)-1] return []byte("{" + string(contactContent) + "," + string(introContent) + "}"), nil }
关于临时自定义类型的补充
你的DateTimeUTC类型方案,本质是通过覆盖时间类型的序列化逻辑统一处理UTC。如果不想修改原有结构体定义,上面的两个方案更直接;如果能接受小范围的结构体字段类型调整,将Contact的CreatedAt改为DateTimeUTC,可以彻底避免嵌套序列化冲突,同时无需给结构体实现MarshalJSON。
内容的提问来源于stack exchange,提问作者Big_Boulard
相关产品推荐
相关产品推荐

