Go中JSON字符串值与结构体int字段反序列化类型不匹配如何解决
问题原因
Go 标准库 encoding/json 默认不会做跨类型隐式转换:当结构体字段声明为 int 类型时,JSON 中对应字段如果是带双引号的字符串值,直接调用 json.Unmarshal 会触发类型不匹配错误。
要求字段以整数格式存入 MongoDB 的需求不需要妥协,不需要把字段改成 string 类型存库前再手动转换,以下是生产环境常用的优雅解决方案:
推荐方案:自定义整数类型实现JSON反序列化接口
自定义一个底层为 int 的类型,实现 json.Unmarshaler 接口,专门兼容从字符串格式的数字值解析,同时完全不影响 BSON 序列化到 MongoDB 的逻辑。
实现代码
package main import ( "encoding/json" "fmt" "strconv" ) // StringInt 可同时兼容JSON中数字格式、字符串格式的整数值解析 type StringInt int // UnmarshalJSON 实现自定义JSON反序列化逻辑 func (si *StringInt) UnmarshalJSON(data []byte) error { // 优先尝试按字符串格式解析,去除两端双引号后转整数 if s, err := strconv.Unquote(string(data)); err == nil { num, convErr := strconv.Atoi(s) if convErr != nil { return fmt.Errorf("parse string to int failed, value: %s, err: %w", s, convErr) } *si = StringInt(num) return nil } // 字符串解析失败时,尝试按原生数字格式解析,兼容接口后续改回数字返回的场景 var num int if err := json.Unmarshal(data, &num); err != nil { return fmt.Errorf("value is not valid integer: %s", string(data)) } *si = StringInt(num) return nil } // 业务结构体不需要修改bson标签 type Product struct { Price StringInt `json:"price" bson:"price"` }
方案优势
- 兼容性强:无论外部接口返回的是
"price": "10000"字符串格式,还是"price": 10000纯数字格式,都能正常反序列化 - 零额外成本适配MongoDB:
StringInt底层类型是int,官方MongoDB Go驱动会自动将其序列化为BSON整数类型,不需要额外做类型转换,存库格式完全符合要求 - 业务使用成本低:需要做数值计算时,仅需显式转换为原生int即可:
priceInt := int(product.Price)
不推荐的方案
不要为了快速解析直接把Price字段类型改成string,再在存MongoDB前手动做类型转换:
- 容易遗漏转换逻辑,导致字符串类型的值被写入MongoDB,后续查询、聚合计算会出现隐性bug
- 业务代码中每次使用该字段都需要做转换,维护成本随调用链路增长指数级上升
内容的提问来源于stack exchange,提问作者Someone Special
相关产品推荐
相关产品推荐

