Golang json unmarshal 大整数丢失精度问题

问题介绍

在 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

comments powered by Disqus