问题介绍
在 Golang 中使用 json Unmarshal 将一个 json 解析为不确定的结构 interface{} 时候,会将数字的接收类型默认设置为 float64。
当原 json 结构中的整数太长,会导致转为 float64 超出精度,导致精度丢失。
例子
package main
import (
"bytes"
"encoding/json"
"fmt"
)
var jsonstring = `{
"id": 1130839459432311551,
"id1": 113083945943231,
"id2": 12344556,
"create_time": "2023-03-22 16:58:38",
"labels": []
}`
func f1() {
var data interface{}
err := json.Unmarshal([]byte(jsonstring), &data)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", data)
dataBytes, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Printf("%+s\n", string(dataBytes))
}
func main() {
f1()
}
解决方法
Golang 中提供了 json.NewDecode().UseNumber() 的方式来解决。
UseNumber causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.
func f2() {
var data interface{}
decoder := json.NewDecoder(bytes.NewReader([]byte(jsonstring)))
decoder.UseNumber()
err := decoder.Decode(&data)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", data)
dataBytes, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Printf("%+s\n", string(dataBytes))
}
golang unmarshal string into int64, or marshal int64 to string
在和前端交互的时候,在 json 结构中放大整数的 uid,前端使用 javascript json 处理的时候会掉丢失精度,虽然 javascript 有解决方式,但是后端接口将 int64 转为 string 更直接。
在 Golang 中的解决办法,就是在渲染 json 数据之前,将返回结构体中的 int64 类型的字段 json 标签类型设为 string 即可。
type Data struct {
ID int64 `json:"id,string,omitempty"`
Name string `json:"name,omitempty"`
}
Ref
- Decoder.UseNumber
- Some trouble with JSON and large integers displaying in scientific notation
- JSON unmarshaling with long numbers gives floating point number
- Decoding JSON using json.Unmarshal vs json.NewDecoder.Decode
- 深入理解Go Json.Unmarshal精度丢失之谜
- golang json 避免大整数变为浮点数
- https://stackoverflow.com/questions/21151765/cannot-unmarshal-string-into-go-value-of-type-int64