Go JSON中序列化大整數(shù)精度丟失的問題分析
在 Go 項目中,我們經(jīng)常使用 map[string]interface{} 來表示動態(tài)字段,或者用 JSON 序列化對象存入數(shù)據(jù)庫、發(fā)送到 MQ。然而,當(dāng)存儲或傳輸 大整數(shù)(int64) 時,往往會出現(xiàn)精度丟失的問題。本文通過一個示例來詳細(xì)分析原因,并給出解決方案。
場景示例
假設(shè)我們有一個動態(tài) Extra 字段,用于存儲一些擴(kuò)展信息,其中 oldTask 是一個 int64 大整數(shù):
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 模擬 Extra 字段
extra := make(map[string]interface{})
extra["oldTask"] = int64(7587721483007868979)
fmt.Println("【1】原始寫入 int64:")
fmt.Printf("type=%T, value=%v\n\n", extra["oldTask"], extra["oldTask"])
}
輸出:
【1】原始寫入 int64:
type=int64, value=7587721483007868979
在 Go 內(nèi)存中,extra["oldTask"] 正確保存了 int64 值。
JSON 序列化
接下來我們將這個 map 序列化為 JSON 字符串(就像你在 BuildRiskPointsStrategy 中做的):
bytes, _ := json.Marshal(extra)
fmt.Println("【2】json.Marshal 后:")
fmt.Println(string(bytes), "\n")
輸出:
【2】json.Marshal 后:
{"oldTask":7587721483007868979}
Go 的 json.Marshal 對 int64 的處理是安全的,大整數(shù)不會丟失精度。
JSON 反序列化到 map[string]interface{}
然而問題出現(xiàn)了,當(dāng)我們反序列化 JSON 到 map[string]interface{} 時:
var extra2 map[string]interface{}
_ = json.Unmarshal(bytes, &extra2)
fmt.Println("【3】json.Unmarshal 后:")
fmt.Printf("type=%T, value=%v\n\n", extra2["oldTask"], extra2["oldTask"])
輸出:
【3】json.Unmarshal 后:
type=float64, value=7587721483007869000
注意:
- 反序列化后,
extra2["oldTask"]變成了 float64 - 原始的 int64 值
7587721483007868979精度丟失 - 這是 Go 標(biāo)準(zhǔn)庫
encoding/json的默認(rèn)行為:map[string]interface{}中的數(shù)字全部解析成float64。
再轉(zhuǎn)回 int64
如果我們強(qiáng)行把它轉(zhuǎn)回 int64:
lost := int64(extra2["oldTask"].(float64))
fmt.Println("【4】float64 → int64 后:")
fmt.Println("value =", lost)
輸出:
【4】float64 → int64 后:
value = 7587721483007869000
可以看到,數(shù)字已經(jīng)不再精確,丟失了最后幾位。
對比差值
fmt.Println("【5】對比:")
fmt.Println("是否相等:", lost == int64(7587721483007868979))
fmt.Println("差值:", lost-int64(7587721483007868979))
輸出:
【5】對比:
是否相等: false
差值: 79
- 原始值與反序列化后值不一致
- 這就是“精度丟失”的根本原因
問題分析
原因總結(jié):
1.Go 的 encoding/json 對 map[string]interface{} 反序列化時:
- 所有數(shù)字默認(rèn)是
float64 - float64 最大安全整數(shù)范圍是
-2^53 ~ 2^53
2.當(dāng) int64 值超出 2^53 時,float64 表示不精確 → 精度丟失
Go 官方文檔說明:JSON numbers without decimal points are decoded as float64 when the target is interface{}。
解決方案
方案 1:使用字符串存儲大整數(shù)
extra["oldTask"] = fmt.Sprintf("%d", oldTaskInt64)
- JSON 序列化后:
"oldTask":"7587721483007868979" - 寫入數(shù)據(jù)庫 / MQ / ES 時不會丟精度
- 讀取時再用
strconv.ParseInt轉(zhuǎn)回 int64
方案 2:使用json.Number解析
var extra2 map[string]interface{}
decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
decoder.UseNumber() // 使用 json.Number 代替 float64
decoder.Decode(&extra2)
extra2["oldTask"]類型是json.Number- 可以安全轉(zhuǎn)成
int64或string
num, _ := extra2["oldTask"].(json.Number).Int64()
方案 3:使用 struct 明確類型
type RiskExtra struct {
OldTask int64 `json:"oldTask"`
}
- 避免 map[string]interface{} → float64
- JSON 反序列化會直接解析為 int64
結(jié)論
Go map[string]interface{} + JSON 是大整數(shù)丟失精度的高發(fā)場景
精度丟失的原因:JSON 默認(rèn)解析數(shù)字為 float64
解決方案:
- 使用字符串存儲大整數(shù)
- 使用
json.Number - 或者盡量使用 struct 明確類型
到此這篇關(guān)于Go JSON中序列化大整數(shù)精度丟失的問題分析的文章就介紹到這了,更多相關(guān)Go JSON序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go用兩個協(xié)程交替打印100以內(nèi)的奇偶數(shù)的方法詳解
這篇文章主要給大家詳細(xì)介紹了Go用兩個協(xié)程交替打印100以內(nèi)的奇偶數(shù)的示例代碼,文中給大家介紹了兩個實現(xiàn)方法,使用無緩沖的channel和設(shè)置GOMAXPROCS=1,介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08
2026年Go語言開發(fā)中沒有它就不行的10個庫總結(jié)
Go語言以其簡潔高效、并發(fā)安全、跨平臺編譯等特性,在后端服務(wù)、云原生、DevOps 工具等領(lǐng)域占據(jù)重要地位,這篇文章主要介紹了2026年Go語言開發(fā)中沒有它就不行的10個庫,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-05-05

