go语言中json.Unmarshal导致大数字溢出精度问题

11 篇文章 0 订阅
7 篇文章 0 订阅

目前问题是出现在使用了uint64的雪花算法ID中发生的问题,在解析出数据的时候导致精度丢失。以下demo并不是使用转换为字符串方式解决。 

package main

import (
	"encoding/json"
	"fmt"
)

func main() {

    var myjson string
	myjson = `{"id":9723275009654785}`
	fmt.Println("期望结果:", myjson)

	type myjsonStruct struct {
		Id uint64 `json:"id"`
	}
	//定义的结构体以及类型 就可以直接解析 此时就是正确的数值不会超出精度。在你完全掌控的结构内可以自行定义字段和类型。
	var myjsonStruct1 myjsonStruct
	json.Unmarshal([]byte(myjson), &myjsonStruct1)
	fmt.Println(fmt.Sprintf("%+v", myjsonStruct1)) //{Id:9723275009654785}

	//将输出错误的精度数值 【不定义具体结构体时将超出精度的时候会出现错误数值】因为interface在解析的时候会自动转换类型为float64 当int64等超出float64的时候就会出现精度丢失 因为float64实际上比int64可用范围小。
	var myjsonStruct2 interface{}
	json.Unmarshal([]byte(myjson), &myjsonStruct2)
	fmt.Println(fmt.Sprintf("%+v", myjsonStruct2)) //map[id:9.723275009654784e+15] 转出结果9,723,275,009,654,784 少了一位

	//此时会输出正确的数值【此时不想定义结构体,但是还想保证结果正确考虑这种方式】
	var myjsonStruct3 interface{}
	JsonDecode(myjson, &myjsonStruct3) //map[id:9723275009654785]
	fmt.Println(fmt.Sprintf("%+v", myjsonStruct3))


}

func JsonDecode(data string, v interface{}) error {
	d := json.NewDecoder(strings.NewReader(data))
	d.UseNumber()
	err := d.Decode(v)
	if err != nil {
		return err
	}
	return nil
}

总结描述:

1.使用结构体时是正确的结果。因为结构体中类型由明确的定义,此时json.Unmarshal不会统一对数字使用float64类型,就不会存在转换错误的情况

2.使用interface时在出现大数字的情况下例如16位以上的数字可能会出现精度丢失问题。因为此时json.Unmarshal使用了float64

3.使用json.NewDecoder是正确的。为了方便使用上述进行了封装。原理可能是转为字符串实现的。

4.也可以考虑使用json.Number。本质就是一个字符串,只不过是后面你可以自由转换类型

5.自己通过正则将所有数字转为字符串后再json.Unmarshal

目前我需要数字所以选择了简单的处理办法,使用自己封装的JsonDecode方式进行实现。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值