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

Golang中json.Marshal与Unmarshal处理大数字时数值不一致问题

问题复现

复现代码如下:

package main

import (
    "encoding/json"
    "fmt"
)

func t() {
    a := int64(1<<63 - 1)
    fmt.Println(a)
    m := map[string]interface{}{
        "balance": a,
    }

    data, _ := json.Marshal(m)
    m1 := make(map[string]interface{})
    err := json.Unmarshal(data, &m1)
    panicIF(err)
    fmt.Println(int64(m1["balance"].(float64)))
}

func panicIF(err error) {
    if err != nil {
        panic(err)
    }
}

代码运行控制台输出:

9223372036854775807
-9223372036854775808
问题底层原理

你提到的「JSON不建议使用number类型存储大于2^53的数字,这类大数值应当改用string类型存储」的说法完全准确,这是跨语言JSON传输的通用约定,底层逻辑如下:

  • JSON标准本身没有对number类型做整数、浮点数的明确区分,绝大多数编程语言的标准JSON解析库,在不知道字段预期类型的场景下(比如解析到interface{}/any类型、无结构的map类型),都会默认将JSON number按照IEEE 754 双精度浮点数(float64)规则存储。
  • float64的有效尾数长度为52位,加上隐含的1位前置整数位,总共可以无误差精确表示的整数范围是[-2^53, 2^53],超出这个范围的整数无法被float64精确存储,必然出现精度丢失。
  • 你的代码中写入的1<<63 - 1是int64类型的最大正整数9223372036854775807,远大于2^53(对应值为9007199254740992)。反序列化时因为目标类型是map[string]interface{},json包无法感知balance字段原本是int64类型,会默认将其解析为float64,转换过程中该值被近似为9223372036854775808,这个值已经超出int64正数的表示上限,强制转换为int64时发生整数溢出,最终得到int64的最小值-9223372036854775808。
正确规避方式
  • 跨语言通用方案:所有超过2^53的整数,在JSON序列化时统一转为string类型传输,接收端拿到字符串后再转换为对应语言的64位整数类型,从根源上避免float64精度丢失问题。
  • Go生态内无跨语言需求的场景:反序列化时使用json.Decoder并开启UseNumber()选项,此时JSON number会被直接解析为json.Number类型(本质是原始数字字符串),不会提前转成float64,使用时调用其Int64()方法即可拿到正确的int64值,示例代码:
import "bytes"

// 替换原有的json.Unmarshal逻辑
m1 := make(map[string]interface{})
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
err := decoder.Decode(&m1)
panicIF(err)
// 取值时转换
balance, err := m1["balance"].(json.Number).Int64()
panicIF(err)
fmt.Println(balance) // 正确输出9223372036854775807
  • 固定结构场景尽量避免用map[string]interface{}接收JSON数据,提前定义对应结构体,将大数字段明确声明为int64/uint64类型,json包反序列化时会直接按照指定类型解析,不会走float64的默认转换逻辑。

内容的提问来源于stack exchange,提问作者Laxmi Prasad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:57:21