最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Go語言中json轉(zhuǎn)換int64精度丟失的問題解決

 更新時間:2026年04月20日 09:30:51   作者:leijmdas  
在Go語言中,JSON轉(zhuǎn)換為`int64`類型時,如果JSON中的數(shù)字過大或過小,可能會導(dǎo)致精度丟失,本文為大家整理了一些可能導(dǎo)致精度丟失的情況以及具體解決方法,希望對大家有所幫助

在Go語言中,JSON轉(zhuǎn)換為`int64`類型時,如果JSON中的數(shù)字過大或過小,可能會導(dǎo)致精度丟失。這是因為JSON標(biāo)準(zhǔn)中并沒有定義整數(shù)類型,而是使用`double`(雙精度浮點(diǎn)數(shù))來表示所有數(shù)字,這在轉(zhuǎn)換為`int64`時可能會造成問題。

導(dǎo)致精度丟失的情況

以下是一些可能導(dǎo)致精度丟失的情況:

1. 大整數(shù):如果JSON中的數(shù)字超出了`int64`的范圍(-2^63 到 2^63-1),那么在轉(zhuǎn)換時可能會丟失精度。

2. 浮點(diǎn)數(shù):如果JSON中的數(shù)字是一個浮點(diǎn)數(shù),那么在轉(zhuǎn)換為`int64`時,可能會丟失小數(shù)點(diǎn)后的數(shù)值。

3. 負(fù)數(shù):對于負(fù)數(shù),如果它超出了`int64`的表示范圍,轉(zhuǎn)換時同樣會丟失精度。

解決方法

為了解決這個問題,你可以采取以下幾種方法:

1.使用`json.Number`類型:在解析JSON時,可以使用`json.Number`類型來保留原始的數(shù)值表示,然后再根據(jù)需要轉(zhuǎn)換為`int64`。

import (
    "encoding/json"
    "fmt"
    "math/big"
)
func main() {
    jsonStr := `{"number": "9223372036854775808"}` // 超出int64范圍的數(shù)字
    var data map[string]json.Number
    err := json.Unmarshal([]byte(jsonStr), &data)
    if err != nil {
        panic(err)
    }
    number := data["number"]
    num := new(big.Int)
    num, ok := number.Int64()
    if !ok {
        num, _ = new(big.Int).SetString(string(number), 10)
        fmt.Printf("轉(zhuǎn)換為big.Int: %s\n", num.String())
    } else {
        fmt.Printf("轉(zhuǎn)換為int64: %d\n", num)
    }
}

2.使用第三方庫:使用如`go.mongodb.org/mongo-driver/bson`這樣的庫,它們可能提供了更靈活的整數(shù)處理方式。

3.手動處理:在解析JSON之前,你可以手動檢查數(shù)字的大小,如果超出了`int64`的范圍,可以提前進(jìn)行處理。

4.明確JSON格式:在生成JSON時,確保數(shù)字在`int64`的范圍內(nèi),或者使用字符串來表示大整數(shù)。

請注意,處理大整數(shù)或浮點(diǎn)數(shù)時,可能需要使用`math/big`包中的`Int`類型來避免精度丟失。

jsoniter "github.com/json-iterator/go"
func Test0008_Jsoniter_Marshal(t *testing.T) {
    order := Order{
       Id:         baseutils.SnowflakeNextVal(),
       OrderId:    "12345678",
       Money:      99.99,
       CreateTime: time.Now(), // 2023-12-05T16:19:33.943989108+08:00
       Extend:     map[string]string{"name": "張三"},
    }
    // 使用1:直接轉(zhuǎn)成字符串
    jsonStr, _ := jsoniter.MarshalToString(order)
    fmt.Println("jsonStr:", jsonStr)
    // 使用2:直接轉(zhuǎn)成字節(jié)數(shù)組
    jsonByteArr, _ := jsoniter.Marshal(order)
    fmt.Println("jsonByteArr:", jsonByteArr)
    // 使用3:反序列化之字符串轉(zhuǎn)結(jié)構(gòu)體
    str := `{"id":666, "order_id":"12345678", "money": 99.99, "create_time":"2023-12-05T16:19:33.943989108+08:00", "extend":{"name":"張三"}}`
    var order2 Order
    err := jsoniter.UnmarshalFromString(str, &order2)
    if err != nil {
       fmt.Println("err2:", err)
    }
    fmt.Println("order2:", order2)
    // 使用4:反序列化之字節(jié)數(shù)組轉(zhuǎn)結(jié)構(gòu)體
    var order3 Order
    var jsonNew = jsoniter.ConfigCompatibleWithStandardLibrary
    // 自適應(yīng)類型
    extra.RegisterFuzzyDecoders()
    err = jsonNew.Unmarshal(jsonByteArr, &order3)
    if err != nil {
       fmt.Println("err3:", err)
    }
    fmt.Println("order3:", order3)
}
???????order3: {572839995925069824 12345678 99.99 2024-04-29 17:41:37.8819085 +0800 CST map[name:張三]}

知識擴(kuò)展

處理 Go 語言 JSON 轉(zhuǎn)換時 int64 精度丟失的問題,本質(zhì)是 encoding/json 默認(rèn)將 JSON 數(shù)字解析為 float64 導(dǎo)致的。由于 float64 僅能精確表示 ±2^53 范圍內(nèi)的整數(shù),超出這個范圍的 64 位整數(shù)在轉(zhuǎn)換時會被舍入或截斷,從而引發(fā)精度丟失。

針對此問題,業(yè)界主要有三種不同的解決方案,它們各有優(yōu)劣,你可以根據(jù)自己的具體場景來權(quán)衡選擇。

方案一:使用 json.Number (最輕量、最精準(zhǔn))

這種方案通過延遲類型轉(zhuǎn)換來避免精度丟失。你可以將結(jié)構(gòu)體中可能包含大整數(shù)的字段聲明為 json.Number 類型(本質(zhì)是字符串),它就像一個“容器”,暫存原始的 JSON 數(shù)字文本。之后,你可以按需通過調(diào)用其 .Int64() 方法來獲得精確的 int64 值。

package main
import (
	"encoding/json"
	"fmt"
)
type MyData struct {
	// 將可能超限的整數(shù)字段聲明為 json.Number
	LargeID json.Number `json:"id"`
}
func main() {
	jsonStr := `{"id": 9223372036854775807}`
	var data MyData
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		panic(err)
	}
	// 安全地將 json.Number 轉(zhuǎn)換為 int64
	id, err := data.LargeID.Int64()
	if err != nil {
		panic(err) // 處理轉(zhuǎn)換錯誤
	}
	fmt.Printf("轉(zhuǎn)換后的 int64 值: %d\n", id)
}

關(guān)鍵點(diǎn)json.Number 字段需要手動調(diào)用 .Int64() 方法進(jìn)行轉(zhuǎn)換,這是獲取精確值的必要步驟,不可省略。

方案二:使用 json:",string" 標(biāo)簽 (最優(yōu)雅、最常用)

此方案利用結(jié)構(gòu)體標(biāo)簽,讓 encoding/json 在編解碼時自動將該字段在 JSON 字符串和 Go 數(shù)值之間進(jìn)行轉(zhuǎn)換。它在你無法改變前端(如 JavaScript)只接收字符串的情況下尤其有用。

package main

import (
	"encoding/json"
	"fmt"
)

type MyData struct {
	// 使用 json:",string" 標(biāo)簽,讓 ID 在 JSON 中以字符串形式傳遞
	LargeID int64 `json:"id,string"`
}

func main() {
	jsonStr := `{"id": "9223372036854775807"}`
	var data MyData
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		panic(err)
	}
	fmt.Printf("Unmarshal 得到的 int64 值: %d\n", data.LargeID)
}

方案三:自定義 UnmarshalJSON 方法 (終極可控)

此方案通過實現(xiàn) json.Unmarshaler 接口來完全控制一個自定義類型的解析過程,獲得最高的靈活性。你可以將解析邏輯封裝成一個自定義類型,并在需要的地方復(fù)用。

package main

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// 定義一個新的類型,并為其實現(xiàn) UnmarshalJSON 接口
type PreciseInt int64

func (pi *PreciseInt) UnmarshalJSON(b []byte) error {
	// 1. 先解析到 json.Number
	var n json.Number
	if err := json.Unmarshal(b, &n); err != nil {
		return err
	}
	// 2. 再從 json.Number 安全地轉(zhuǎn)換為 int64
	i, err := n.Int64()
	if err != nil {
		return err
	}
	*pi = PreciseInt(i)
	return nil
}

type MyData struct {
	LargeID PreciseInt `json:"id"`
}

func main() {
	jsonStr := `{"id": 9223372036854775807}`
	var data MyData
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		panic(err)
	}
	fmt.Printf("轉(zhuǎn)換后的 int64 值: %d\n", data.LargeID)
}

方案對比與選擇建議

為了幫助你更直觀地選擇,我為你整理了以下對比表格:

對比維度方案一:json.Number方案二:json:",string" 標(biāo)簽方案三:自定義 UnmarshalJSON
核心機(jī)制使用 json.Number 類型暫存原始 JSON 數(shù)字字符串利用標(biāo)簽 ,string 實現(xiàn) JSON 字符串與 Go 數(shù)值的自動轉(zhuǎn)換為自定義類型實現(xiàn) json.Unmarshaler 接口,完全掌控解析過程
代碼侵入性:只需修改結(jié)構(gòu)體字段類型:只需在結(jié)構(gòu)體標(biāo)簽中添加 ,string中等:需要定義新類型并實現(xiàn)接口
對前端的影響:前端接收到的仍是 Number:前端需處理 string 類型可控:可根據(jù)實現(xiàn)邏輯決定 JSON 中的格式
性能開銷中等:涉及額外類型轉(zhuǎn)換,有約 2-3 倍開銷:性能損耗極小中等:類似 json.Number,取決于實現(xiàn)
靈活性與擴(kuò)展性:功能相對單一:功能單一極高:可根據(jù)需求定制任意邏輯
推薦場景處理動態(tài)結(jié)構(gòu)第三方 API 的 JSON 數(shù)據(jù)時JavaScript 前端交互時的首選方案需要對特定字段進(jìn)行復(fù)雜校驗、轉(zhuǎn)換或類型限制

總的來說:

  • 如果你需要和前端(尤其是 JavaScript)交互,方案二 (json:",string" 標(biāo)簽) 是最直接、優(yōu)雅的選擇。
  • 如果你正在處理一個結(jié)構(gòu)不固定的 JSON 數(shù)據(jù),方案一 (json.Number) 能提供最大的靈活性。
  • 如果以上方案都無法滿足你的特定需求,方案三 (自定義 UnmarshalJSON) 為你提供了終極的掌控力。

到此這篇關(guān)于詳解Go語言中json轉(zhuǎn)換int64精度丟失的問題解決的文章就介紹到這了,更多相關(guān)Go語言json轉(zhuǎn)int64精度丟失解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go?gRPC服務(wù)proto數(shù)據(jù)驗證進(jìn)階教程

    Go?gRPC服務(wù)proto數(shù)據(jù)驗證進(jìn)階教程

    這篇文章主要為大家介紹了Go?gRPC服務(wù)proto數(shù)據(jù)驗證進(jìn)階教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go語言開發(fā)代碼自測絕佳go?fuzzing用法詳解

    Go語言開發(fā)代碼自測絕佳go?fuzzing用法詳解

    這篇文章主要為大家介紹了Go語言開發(fā)代碼自測絕佳go?fuzzing用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go語言中的訪問權(quán)限控制

    Go語言中的訪問權(quán)限控制

    在?go?中進(jìn)行權(quán)限管理時,推薦使用?grouper、casbin?和?sentry?框架,grouper?適合基于角色的訪問控制,casbin?提供高級?rbac?功能,而?sentry?提供云托管權(quán)限服務(wù)和豐富的功能集,包括多因素認(rèn)證和活動審核,這些框架有助于在電子商務(wù)網(wǎng)站等實際場景中實施細(xì)粒度的訪問控制
    2024-08-08
  • Golang?中的json.Marshal問題總結(jié)(推薦)

    Golang?中的json.Marshal問題總結(jié)(推薦)

    這篇文章主要介紹了Golang中的json.Marshal問題總結(jié),本文通過一個例子給大家詳細(xì)講解,本次提出的問題中,我們不難注意到其中的time.Time是一個匿名(Anonymous)字段,而這個就是答案的由來,需要的朋友可以參考下
    2022-06-06
  • Go語言CSP并發(fā)模型goroutine及channel底層實現(xiàn)原理

    Go語言CSP并發(fā)模型goroutine及channel底層實現(xiàn)原理

    這篇文章主要為大家介紹了Go語言CSP并發(fā)模型goroutine?channel底層實現(xiàn)原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • go MethodByName()不能獲取私有方法的解決

    go MethodByName()不能獲取私有方法的解決

    本文主要介紹了go MethodByName()不能獲取私有方法的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Golang拾遺之自定義類型和方法集詳解

    Golang拾遺之自定義類型和方法集詳解

    golang拾遺主要是用來記錄一些遺忘了的、平時從沒注意過的golang相關(guān)知識。這篇文章主要整理了一下Golang如何自定義類型和方法集,需要的可以參考一下
    2023-02-02
  • go語言?http模型reactor示例詳解

    go語言?http模型reactor示例詳解

    這篇文章主要介紹了go語言?http模型reactor,接下來看一段基于reactor的示例,這里運(yùn)行通過?go?run?main.go,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • Golang利用位運(yùn)算實現(xiàn)為程序加速

    Golang利用位運(yùn)算實現(xiàn)為程序加速

    這篇文章主要為大家詳細(xì)介紹了如何在Golang中利用位運(yùn)算實現(xiàn)為程序加速功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-08-08
  • 詳解Golang開啟http服務(wù)的三種方式

    詳解Golang開啟http服務(wù)的三種方式

    這篇文章主要介紹了詳解Golang開啟http服務(wù)的三種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評論

库尔勒市| 巴林左旗| 顺昌县| 綦江县| 博野县| 凤城市| 永修县| 巴彦县| 壤塘县| 信阳市| 横峰县| 锡林浩特市| 临湘市| 大足县| 克山县| 周至县| 安顺市| 平阴县| 大埔区| 新丰县| 锦州市| 梁河县| 上林县| 滦南县| 泸定县| 交城县| 从化市| 延庆县| 滨州市| 察雅县| 延津县| 文山县| 桂东县| 麦盖提县| 昌邑市| 同德县| 丹江口市| 海城市| 怀宁县| 博罗县| 陇西县|