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

先说一个核心结论:你往 map[string]interface{} 里扔一个 {"id": 42},取出来的时候,id 的类型一定是 float64,值是 42.0。这不是 Go 的锅,是它严格遵循了 JSON 规范。下面展开讲讲到底怎么回事,以及怎么绕开这个坑。
这可不是什么 bug,而是 Go 老老实实遵循 RFC 8259 的结果。JSON 规范里并没有整数和浮点数的区别,只有一种叫“Number”的数字类型——123、123.0、1.23e+2 都算 Number。Go 的 encoding/json 包为了设计简单、跨语言一致,把所有 JSON Number 都默认解析成 float64。你传给 map[string]interface{} 一个 {"id": 42},拿出来一查,类型是 float64,值是 42.0。就是这么直接,没商量。
好,现在你写 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 在解析阶段就已经失真了。真要稳妥,还得靠下面的方法。
一旦数字超过 2^53 - 1(也就是 9007199254740991),float64 就无法精确表示低比特位了。典型场景:前端传 "id": 12345678901234567890,后端收到之后变成了 12345678901234567168。误差出现在 Unmarshal 阶段,后面再怎么转都晚了。
正确做法只有两个方向:
string,或者加 json:",string" 标签Decoder.UseNumber(),字段类型写成 json.Number,然后调 .Int64()(注意如果数字带小数点会 panic)千万别指望 json.Unmarshal 自动猜你是想要 int 还是 float——它只按规范办事。你得主动控制解析路径,否则精度丢失防不胜防。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8