json.Unmarshal() 反序列化字节流到 interface{} 对象,字段 int/int64 类型出现精度丢失

简介: json.Unmarshal() 反序列化字节流到 interface{} 对象,字段 int/int64 类型出现精度丢失

问题描述

今天遇到一个 json.Unmarshal() 反序列化字节流到 interface{} 对象,int/int64 类型出现精度丢失的问题,记录一下。下面是网上其他同学的类似的代码,跟我的场景很像,所以直接拿过来作为案发现场代码用了。

jsonStr := `{"id":3861708980690657283}`
  result := make(map[string]interface{})
  err := json.Unmarshal([]byte(jsonStr), &result)
  if err != nil {
    fmt.Println(err)
  }
  id := result["id"]
  fmt.Printf("type=%T, val=%v\n",id, id)

输出

type=float64, val=3.861708980690657e+17

反序列化得到的 id 字段变成了 float64 类型,值输出形式也变成了科学计数法形式,这当然难不倒我,略一百度,就查到了 json.Unmarshal() 反序列化字节流到 interface{} 对象时,如果原来是 int 类型,会被反序列化成 float64 类型,网上的解决方案是对 int 字段进行类型强转

id := int64(result["id"].(float64)) // 先强转成 float64类型,再强转成int64 类型
  fmt.Printf("type=%T, val=%v\n",id, id)

输出

type=int, val=3861708980690657280

查看输出结果,可以发现,类型变成了 int 类型,val 表现形式也变成了整数形式,但是出现了精度丢失,原来值是 3861708980690657283,变成了 3861708980690657280,最后一位的精度丢失了。

再次开始网上冲浪,通过参考中提到的 2 篇博客发现了有 2 种解决方案:

解决方案

1、使用 decode+UseNumber()

不使用 json.Unmarshal() 来反序列对象,而是采用 decode+UseNumber() 来实现反序列化。

jsonStr := `{"id":3861708980690657283}`
  result := make(map[string]interface{})
  decoder := json.NewDecoder(bytes.NewBufferString(jsonStr))
  decoder.UseNumber() // 指定使用 Number 类型
  err := decoder.Decode(&result)
  if err != nil {
    fmt.Println(err)
  }
  id := result["id"]
  fmt.Printf("type=%T, val=%v\n",id, id)

输出

type=json.Number, val=3861708980690657283

输出结果精度没有丢失,类型是 json.Number。如果想把 id 转换成 int4 类型,需要先转换成字符串,再强转成 int64 类型

aaa, err := strconv.ParseInt(fmt.Sprintf("%v", id), 10, 64)  // 如果想把 id 转换成 int4 类型,需要先转换成字符串,再强转成 int64 类型
  fmt.Printf("type=%T, val=%v\n",aaa, aaa)  // 输出 type=int64, val=3861708980690657283

2、反序列化的对象改成不是 interface{}, 而是自定义结构体

可以发现上面先后遇到的这两个问题,无论是科学计数法输出,还是精度丢失,都是发生在 Unmarshal反序列化字节流到 interface{} 对象 上,如果如果不是 interface{} 对象,是不会有这个问题的,所以另一种解决方案是,自定义结构体,明确指定每个字段的类型,这样一切都会如你所愿,不会遇到上面任何一个问题。

type Student struct {
    ID int64 `json:"id"`
  }
  jsonStr := `{"id":3861708980690657283}`
  var result Student
  err := json.Unmarshal([]byte(jsonStr), &result)
  if err != nil {
    fmt.Println(err)
  }
  id := result.ID
  fmt.Printf("type=%T, val=%v\n",id, id)

输出

type=int64, val=3861708980690657283

by the way

网友建议前后端在使用 int64 类型进行交互时,尽量将 int64 转成 string 来传输。

参考:[系列] Go - json.Unmarshal 遇到的小坑golang int64 json.Unmarshal精度丢失问题并解决

相关文章
|
5月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
277 1
|
5月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
296 2
|
10月前
|
JSON JavaScript 前端开发
Go语言JSON 序列化与反序列化 -《Go语言实战指南》
本文介绍了 Go 语言中使用 `encoding/json` 包实现 JSON 与数据结构之间的转换。内容涵盖序列化(`Marshal`)和反序列化(`Unmarshal`),包括基本示例、结构体字段标签的使用、控制字段行为的标签(如 `omitempty` 和 `-`)、处理 `map` 和切片、嵌套结构体序列化、反序列化未知结构(使用 `map[string]interface{}`)以及 JSON 数组的解析。最后通过表格总结了序列化与反序列化的方法及类型要求,帮助开发者快速掌握 JSON 数据处理技巧。
|
12月前
|
Python Windows
[oeasy]python076_int这个词怎么来的_[词根溯源]整数类型_int_integer_touch
本文探讨了“int”一词的起源及其与整数类型的关联。通过词根溯源,揭示“int”来源于“integer”,意为“完整的数”,与零碎的分数相对。同时分析了相关词汇如“tact”(接触)、“touch”(触摸)及衍生词,如“tangential”(切线的)、“intagible”(无形的)和“integral”(完整的、不可或缺的)。文章还结合编程语言特性,解释了Python作为动态类型、强类型语言的特点,并总结了整型变量的概念与意义。最后预告了后续内容,提供了学习资源链接。
427 11
|
12月前
|
存储 C语言 Python
[oeasy]python077_int类型怎么用_整数运算_integer_进制转化_int类
本文主要讲解了Python中`int`类型的应用与特性。首先回顾了`int`词根的溯源,探讨了整型变量的概念及命名规则(如匈牙利命名法)。接着分析了整型变量在内存中的存储位置和地址,并通过`type()`和`id()`函数验证其类型和地址。还介绍了整型变量的运算功能,以及如何通过`int()`函数将字符串转化为整数,支持不同进制间的转换(如二进制转十进制)。此外,文章提及了关键字`del`的使用场景,对比了Python与C语言中`int`的区别,并总结了整型与字符串类型的差异,为后续深入学习奠定基础。
301 1
|
XML JSON 数据可视化
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
本文详细介绍了不同数据集格式之间的转换方法,包括YOLO、VOC、COCO、JSON、TXT和PNG等格式,以及如何可视化验证数据集。
4266 1
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
421 4
|
前端开发 开发者
如何理解 package.json 中的 proxy 字段?
`package.json` 中的 `proxy` 字段用于配置代理服务器,帮助前端开发中解决跨域问题及模拟后端响应。其基本概念、使用场景及配置方法将在本文中详细探讨,助力开发者高效调试与测试。
469 4
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
696 1
|
JSON Java 数据格式
springboot中表字段映射中设置JSON格式字段映射
springboot中表字段映射中设置JSON格式字段映射
667 1