You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:12:22