在go語言中處理json數(shù)據(jù)時,當(dāng)使用`json.unmarshal`將包含大整數(shù)(如64位整數(shù))的json解析到`map[string]interface{}`時,這些整數(shù)可能會被默認(rèn)轉(zhuǎn)換為`float64`,導(dǎo)致精度丟失。本文將詳細(xì)介紹兩種有效方法來避免這種問題:一是利用`json.decoder`的`usenumber()`方法將數(shù)字解析為`json.number`類型,再手動轉(zhuǎn)換;二是定義明確的go結(jié)構(gòu)體,直接將大整數(shù)類型指定為`uint64`或`int64`進(jìn)行解碼。
在Go語言的encoding/json包中,當(dāng)使用json.Unmarshal將JSON數(shù)據(jù)解析到interface{}類型(例如map[string]interface{})時,它會將JSON中的數(shù)字字面量默認(rèn)解析為Go的float64類型。對于不超出float64精度范圍的整數(shù)而言,這通常不是問題。然而,當(dāng)JSON中包含的整數(shù)值超過float64所能精確表示的最大整數(shù)(即2^53)時,就會發(fā)生精度丟失。例如,一個64位整數(shù)(如4418489049307132905)在轉(zhuǎn)換為float64后,其低位信息可能會被截斷或四舍五入。
以下是兩種在Go中解析JSON時保留64位整數(shù)值的解決方案。
encoding/json包提供了一個Decoder類型,它比直接使用json.Unmarshal提供了更精細(xì)的控制。通過Decoder的UseNumber()方法,我們可以指示解碼器將所有JSON數(shù)字解析為json.Number類型,而不是默認(rèn)的float64。json.Number實際上是一個字符串類型,它保留了數(shù)字的原始字符串表示,從而避免了任何潛在的精度損失。之后,我們可以根據(jù)需要將其轉(zhuǎn)換為int64或uint64。
package main import ( "bytes" "encoding/json" "fmt" "strconv" ) func main() { body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`) // 創(chuàng)建一個map來存儲解析后的數(shù)據(jù) dat := make(map[string]interface{}) // 創(chuàng)建一個新的JSON解碼器 d := json.NewDecoder(bytes.NewBuffer(body)) // 啟用UseNumber(),將所有數(shù)字解析為json.Number類型 d.UseNumber() // 解碼JSON數(shù)據(jù) if err := d.Decode(&dat); err != nil { panic(err) } // 訪問解析后的數(shù)據(jù) tags, ok := dat["tags"].([]interface{}) if !ok { panic("tags not found or not an array") } // 遍歷標(biāo)簽并處理ID for i, tag := range tags { tagMap, ok := tag.(map[string]interface{}) if !ok { fmt.Printf("tag %d is not a map\n", i) continue } idNum, ok := tagMap["id"].(json.Number) if !ok { fmt.Printf("tag %d id is not a json.Number\n", i) continue } // 將json.Number轉(zhuǎn)換為uint64 // 根據(jù)實際數(shù)據(jù)范圍選擇ParseInt或ParseUint id64, err := strconv.ParseUint(string(idNum), 10, 64) if err != nil { fmt.Printf("Error parsing id %s: %v\n", idNum, err) continue } fmt.Printf("tag: %d id: %d (Type: %T)\n", i, id64, id64) } }
這種方法提供了最大的靈活性,但需要額外的類型斷言和字符串轉(zhuǎn)換步驟。
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
更Go慣用且通常更推薦的方法是定義一個與JSON結(jié)構(gòu)相匹配的Go結(jié)構(gòu)體(struct)。通過明確指定結(jié)構(gòu)體字段的類型為uint64或int64,json.Unmarshal可以直接將JSON中的數(shù)字解析到這些字段,而無需經(jīng)過float64的中間轉(zhuǎn)換。
package main import ( "encoding/json" "fmt" ) // 定義與JSON結(jié)構(gòu)對應(yīng)的Go結(jié)構(gòu)體 type Tag struct { ID uint64 `json:"id"` // 明確指定ID為uint64類型 } type Data struct { Tags []Tag `json:"tags"` // 包含Tag結(jié)構(gòu)體的切片 } func main() { body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`) var data Data // 直接將JSON數(shù)據(jù)解碼到自定義結(jié)構(gòu)體 if err := json.Unmarshal(body, &data); err != nil { panic(err) } // 訪問解析后的數(shù)據(jù) for i, tag := range data.Tags { fmt.Printf("tag: %d id: %d (Type: %T)\n", i, tag.ID, tag.ID) } }
這種方法更具結(jié)構(gòu)化,代碼更簡潔,類型安全,且易于維護(hù)。對于已知JSON結(jié)構(gòu)的場景,這是首選方案。
在Go語言中解析JSON數(shù)據(jù)時,為了避免64位整數(shù)值在默認(rèn)解碼過程中被轉(zhuǎn)換為float64并導(dǎo)致精度丟失,我們有兩種主要的策略。第一種是利用json.Decoder的UseNumber()方法將數(shù)字解析為json.Number字符串,然后手動轉(zhuǎn)換為int64或uint64。第二種是定義與JSON結(jié)構(gòu)相對應(yīng)的Go結(jié)構(gòu)體,并明確指定大整數(shù)字段的類型為int64或uint64。這兩種方法都能有效解決精度問題,開發(fā)者應(yīng)根據(jù)實際需求和JSON結(jié)構(gòu)的復(fù)雜性選擇最合適的方案。
以上就是Go中解析JSON時保留64位整數(shù)值的方法的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號