解決Go?Json?Unmarshal反序列化丟失數(shù)字精度問題
現(xiàn)象
業(yè)務(wù)會(huì)使用 id生成器 產(chǎn)生的 分布式唯一ID,長(zhǎng)度比較長(zhǎng)。代碼反序列化時(shí),出現(xiàn)精度丟失,導(dǎo)致線上故障。
package main import ( "testing" "time" "github.com/bytedance/sonic" "github.com/stretchr/testify/assert" ) func TestPrintAttr(t *testing.T) { amap := map[string]any{ "psm_businessline_ref": map[string]any{ "id": 1691071059696833999, }, } amapStr, err := sonic.MarshalString(amap) assert.Nil(t, err) t.Log("\n", amapStr) m1 := make(map[string]any) err = sonic.UnmarshalString(amapStr, &m1) assert.Nil(t, err) }
原因
- 反序列化時(shí),對(duì)于數(shù)值類型的value,默認(rèn)會(huì)反序列化成
float64
類型。 - float64可以存儲(chǔ)的最大整數(shù)是52位尾數(shù)全位1且指數(shù)部分為最大
0x07FEF FFFF FFFF FFFF
(0x001F FFFF FFFF FFFF)16 = (9007199254740991)10
(0x07EF FFFF FFFF FFFF)16 = (9218868437227405311)10
也就是理論上數(shù)值超過9007199254740991(長(zhǎng)度=16)就可能會(huì)出現(xiàn)精度缺失。
10進(jìn)制數(shù)值的有效數(shù)字是16位,一旦超過16位大概率會(huì)有缺失精度的問題
一般分布式唯一id是20位長(zhǎng)度,所以必然出現(xiàn)精度缺失。
參考:
解決方案
使用 json.Decoder 來代替 json.Unmarshal 方法
package main import ( "testing" "time" "github.com/bytedance/sonic" "github.com/stretchr/testify/assert" ) func TestPrintAttr(t *testing.T) { amap := map[string]any{ "psm_businessline_ref": map[string]any{ "id": 1691071059696833999, }, } amapStr, err := sonic.MarshalString(amap) assert.Nil(t, err) t.Log("\n", amapStr) rightM := make(map[string]any) if len(amapStr) > 0 { de := jsoniter.NewDecoder(bytes.NewReader([]byte(amapStr))) de.UseNumber() err := de.Decode(&rightM) if err != nil { t.Fatal(err) } } }
json.Number
本質(zhì)是string
,反序列化的時(shí)候?qū)?strong>json的數(shù)值轉(zhuǎn)成字符串,而字符串不會(huì)有精度丟失問題,所以沒有問題。json.Number
如下:
package json // A Number represents a JSON number literal. type Number string
到此這篇關(guān)于解決Go Json Unmarshal反序列化丟失數(shù)字精度問題的文章就介紹到這了,更多相關(guān)Go Json Unmarshal內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go使用Gin+mysql實(shí)現(xiàn)增刪改查的詳細(xì)實(shí)例
golang本身沒有提供連接mysql的驅(qū)動(dòng),但是定義了標(biāo)準(zhǔn)接口供第三方開發(fā)驅(qū)動(dòng),下面這篇文章主要給大家介紹了關(guān)于Go使用Gin+mysql實(shí)現(xiàn)增刪改查的相關(guān)資料,需要的朋友可以參考下2022-12-12golang中l(wèi)og包自定義輸出日志格式與寫入到文件
這篇文章主要給大家介紹了關(guān)于golang中l(wèi)og包自定義輸出日志格式與寫入到文件的相關(guān)資料,日志輸出在任何項(xiàng)目中都極其重要,是有助于后續(xù)我們排查解決程序BUG,需要的朋友可以參考下2023-06-06go-micro開發(fā)RPC服務(wù)以及運(yùn)行原理介紹
這篇文章介紹了go-micro開發(fā)RPC服務(wù)的方法及其運(yùn)行原理,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07golang gin 框架 異步同步 goroutine 并發(fā)操作
這篇文章主要介紹了golang gin 框架 異步同步 goroutine 并發(fā)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12