go解析json大整数时默认转float64导致精度丢失,应使用json.number或string字段配合",string"标签,并约定前端以字符串形式传输超53位整数。

Go 默认把 JSON 数字当 float64 解析,精度早丢了
只要 JSON 里出现 12345678901234567890 这种超 9007199254740991(即 2^53 - 1)的整数,json.Unmarshal 就会把它塞进 float64 —— 此时精度已不可逆丢失,哪怕你字段声明的是 int64 也无济于事。
常见错误现象:map[string]interface{} 解析后取 extra["id"],再强制转 int64 报 panic;或值看似正常,但最后几位是错的(比如 7587721483007868979 变成 7587721483007869000)。
根本原因不是 Go 的 bug,而是 float64 表达整数的天然限制。别指望靠“多试几次类型断言”绕过去。
用 json.Number 接收关键字段,不自动转、不丢字
json.Number 是标准库提供的轻量容器,本质是字符串,只存原始 JSON 字符序列,不触发任何解析。
实操建议:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 结构体字段显式声明为
json.Number,例如:ID json.Number `json:"id"` - 需要转整数时,调用
.Int64()—— 它内部做了合法性和溢出检查,比strconv.ParseInt(n.String(), 10, 64)更安全 - 如果 ID 可能超
int64范围(比如 128 位雪花 ID),直接用.String()拿原始文本,传给前端或存 DB 都没问题 - 别对
json.Number做加减乘除,它不是数值类型;要算先转,且必须检查返回 error
全局启用 UseNumber() 配合手动解析
如果你没法改结构体定义(比如处理动态 map[string]interface{} 或第三方 SDK 返回的泛型数据),就得在解码器层面干预。
实操建议:
- 创建
json.Decoder实例后立刻调用.UseNumber(),例如:dec := json.NewDecoder(r); dec.UseNumber() - 这样所有 JSON 数字都会以
json.Number形式存入map[string]interface{},而不是默认的float64 - 后续从
map取值时,先断言为json.Number,再调.Int64()或.String() - 注意:别用
json.RawMessage替代——它只是延迟解析,后面仍可能掉进float64陷阱
前端必须发字符串,Go 层才来得及救
Go 用 json.Number 或 string 字段也白搭,如果前端发的是 {"id": 12345678901234567890}(没引号),那这个数字在 JS 序列化时就已经被 JSON.stringify 转成 float64 了,Go 根本收不到原始文本。
所以前后端必须约定:
- 所有可能超
2^53 - 1的字段,前端 JSON 必须写成字符串:{"id": "12345678901234567890"} - Go 结构体对应字段加
json:",string"标签,例如:ID string `json:"id,string"` - 这样 Go 不会尝试解析数字,直接把引号里的内容当字符串收下,零损耗
最容易被忽略的一点:精度丢失往往发生在前端解析响应那一刻,而不是你在 Go 里做运算的时候。只要 JSON 字符串里数字没加引号,问题就已注定。










