为什么Golang的json.Unmarshal处理含"e"和"E"字段的JSON时会出错?
问题1 反序列化报错的原因
Go标准库encoding/json包匹配JSON键与结构体json标签的逻辑分为两步:
- 优先进行精确匹配,即JSON键与标签值完全一致才会绑定字段
- 精确匹配失败后,会 fallback 到大小写不敏感的模糊匹配
你定义的message结构体仅声明了json:"e"标签的string类型字段,反序列化{"e": "foo", "E": 1}时:
- JSON键
e精确匹配到EventType字段,成功赋值为"foo" - JSON键
E找不到精确匹配的标签,触发模糊匹配后命中json:"e"对应的EventType字段,此时尝试将数字1赋值给string类型字段,就抛出了类型不匹配的错误。
而messageUppercaseE结构体同时声明了json:"E"标签,JSON键E会优先精确匹配到对应的uint64类型字段,不会触发模糊匹配,因此反序列化正常。
问题2 原生实现反序列化的方案
不需要引入第三方库,可任选以下两种方案实现:
方案1:补充占位字段承接大写E键值
在message结构体中补充对应E键的字段,避免触发模糊匹配即可,不需要的字段后续直接忽略使用即可:
type message struct { EventType string `json:"e"` // 补充占位字段,精确匹配JSON的E键,不需要可直接忽略该字段值 UppercaseE uint64 `json:"E"` }
如果不需要保留E键的值,也可以将占位字段的类型定义为interface{}兼容任意值类型。
方案2:自定义反序列化逻辑(无多余字段)
如果不想在结构体中增加多余字段,可以为message类型实现UnmarshalJSON方法,自定义解析逻辑:
import ( "encoding/json" "fmt" ) type message struct { EventType string } func (m *message) UnmarshalJSON(data []byte) error { // 用map承接所有JSON键值,避免模糊匹配问题 var tmp map[string]interface{} if err := json.Unmarshal(data, &tmp); err != nil { return err } // 单独提取e字段做类型校验和赋值 eVal, eOk := tmp["e"] if !eOk { return fmt.Errorf("missing required field e") } eStr, strOk := eVal.(string) if !strOk { return fmt.Errorf("field e is not string type") } m.EventType = eStr return nil }
内容的提问来源于stack exchange,提问作者Dennis Stritzke
相关产品推荐
相关产品推荐

