商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 为什么在 Go 中直接使用 json.Unmarshal 解析数字会变成 float64

为什么在 Go 中直接使用 json.Unmarshal 解析数字会变成 float64

  发布于2026-07-03 阅读(0)

扫一扫,手机访问

JSON 标准里压根没有整数类型,只有一种叫“Number”的抽象数字。Go 的 json.Unmarshal 严格遵循这条规范,把所有数字都解析成 float64——这是铁板钉钉的标准行为。但如果你要处理大整数(比如 ID 或时间戳),就必须主动绕开这条默认路径,要么用 json.Number,要么让结构体字段加上 ",string" 标签,否则精度流失连声招呼都不打。

为什么在 Go 中直接使用 json.Unmarshal 解析数字会变成 float64

先说一个核心结论:你往 map[string]interface{} 里扔一个 {"id": 42},取出来的时候,id 的类型一定是 float64,值是 42.0。这不是 Go 的锅,是它严格遵循了 JSON 规范。下面展开讲讲到底怎么回事,以及怎么绕开这个坑。

json.Unmarshal 把所有 JSON 数字都当 float64 是标准行为

这可不是什么 bug,而是 Go 老老实实遵循 RFC 8259 的结果。JSON 规范里并没有整数和浮点数的区别,只有一种叫“Number”的数字类型——123123.01.23e+2 都算 Number。Go 的 encoding/json 包为了设计简单、跨语言一致,把所有 JSON Number 都默认解析成 float64。你传给 map[string]interface{} 一个 {"id": 42},拿出来一查,类型是 float64,值是 42.0。就是这么直接,没商量。

interface{} 接收时数字必为 float64,断言 int64 会 panic

好,现在你写 var data map[string]interface{} 接 JSON,然后想当然地 data["id"].(int64)——运行时必然 panic,因为底层根本不是 int64,是 float64。常见的踩坑写法包括:

  • int(data["id"].(float64)) — 看起来能跑,但数字超过 253 就悄悄丢精度
  • int64(data["id"].(float64)) — 同样不安全,而且遇到 123.5 这种非整数时逻辑完全不对
  • reflect.TypeOf 判断是否为 int64 — 永远返回 float64,毫无意义

这些写法都基于一个错误假设:Go 会自动帮你识别整数。而事实是,Go 不会帮你猜,你只能自己处理。

想保留整数语义?得靠数值特征判断,不是类型反射

如果非要从 []interface{}map[string]interface{} 里识别“逻辑上的整数”,唯一可靠的办法是:先断言成 float64,再检查它是否数学上等于某个整数:

if num, ok := val.(float64); ok {
    if num == float64(int64(num)) {
        // 是整数,可安全转:int64(num)
    } else {
        // 是浮点数,比如 3.14
    }
}

但注意:int64(num) 对超大数(比如 9223372036854775807)仍然可能截断,因为 float64 在解析阶段就已经失真了。真要稳妥,还得靠下面的方法。

大整数(如 ID、时间戳)必须绕过 float64 中转

一旦数字超过 2^53 - 1(也就是 9007199254740991),float64 就无法精确表示低比特位了。典型场景:前端传 "id": 12345678901234567890,后端收到之后变成了 12345678901234567168。误差出现在 Unmarshal 阶段,后面再怎么转都晚了。

正确做法只有两个方向:

  • 前端把数字当字符串发,后端结构体字段声明为 string,或者加 json:",string" 标签
  • 后端用 Decoder.UseNumber(),字段类型写成 json.Number,然后调 .Int64()(注意如果数字带小数点会 panic)

千万别指望 json.Unmarshal 自动猜你是想要 int 还是 float——它只按规范办事。你得主动控制解析路径,否则精度丢失防不胜防。

本文转载于:https://www.php.cn/faq/2460092.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注