1.问题现象描述

使用 json.Unmarshal(),反序列化时,出现了科学计数法,参考代码如下:

jsonStr := `{"number":1234567}`
result := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonStr), &result)
if err != nil {
fmt.Println(err)
}
fmt.Println(result) // 输出
// map[number:1.234567e+06]

这个问题不是必现,只有当数字的位数大于 6 位时,才会变成了科学计数法。

2.问题影响描述

当数据结构未知,使用 map[string]interface{} 来接收反序列化结果时,如果数字的位数大于 6 位,都会变成科学计数法,用到的地方都会受到影响。

3.引起问题的原因

encoding/json 可以找到答案,看一下这段注释:

// To unmarshal JSON into an interface value,
// Unmarshal stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
// string, for JSON strings
// []interface{}, for JSON arrays
// map[string]interface{}, for JSON objects
// nil for JSON null

是因为当 JSON 中存在一个比较大的数字时,它会被解析成 float64 类型,就有可能会出现科学计数法的形式。

4.问题的解决方案

方案一

强制类型转换,参考代码如下:

jsonStr := `{"number":1234567}`
result := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonStr), &result)
if err != nil {
fmt.Println(err)
}
fmt.Println(int(result["number"].(float64))) // 输出
// 1234567

方案二

尽量避免使用 interface,对 json 字符串结构定义结构体,快捷方法可使用在线工具:https://mholt.github.io/json-to-go/

type Num struct {
Number int `json:"number"`
} jsonStr := `{"number":1234567}`
var result Num
err := json.Unmarshal([]byte(jsonStr), &result)
if err != nil {
fmt.Println(err)
}
fmt.Println(result) // 输出
// {1234567}

方案三

使用 UseNumber() 方法。

jsonStr := `{"number":1234567}`
result := make(map[string]interface{})
d := json.NewDecoder(bytes.NewReader([]byte(jsonStr)))
d.UseNumber()
err := d.Decode(&result)
if err != nil {
fmt.Println(err)
}
fmt.Println(result) // 输出
// map[number:1234567]

这时一定要注意 result["number"] 的数据类型!

fmt.Println(fmt.Sprintf("type: %v", reflect.TypeOf(result["number"])))

// 输出
// type: json.Number

通过代码可以看出 json.Number 其实就是字符串类型:

// A Number represents a JSON number literal.
type Number string

如果转换其他类型,参考如下代码:

// 转成 int64
numInt, _ := result["number"].(json.Number).Int64()
fmt.Println(fmt.Sprintf("value: %v, type: %v", numInt, reflect.TypeOf(numInt))) // 输出
// value: 1234567, type: int64 // 转成 string
numStr := result["number"].(json.Number).String()
fmt.Println(fmt.Sprintf("value: %v, type: %v", numStr, reflect.TypeOf(numStr))) // 输出
// value: 1234567, type: string

[系列] Go - json.Unmarshal 遇到的小坑的更多相关文章

  1. net core 小坑杂记之配置文件读取(不定期更新)

    其实很早就想写了,原想等积累差不多了再写的,但是发现遇到一个当时记下效果会比较好,所以就不定期更新这个系列了,后面获取会整个整理一下. 此篇记载net core入门时踩的一些坑,网上教程太少了,也不规 ...

  2. Vue中应用CORS实现AJAX跨域,及它在 form data 和 request payload 的小坑处理

    基本概念部分(一):理解CORS 说道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域资源共享"(Cross-origin resource sharing),它是一个W3 ...

  3. bottle的几个小坑

    距离我在<web.py应用工具库:webpyext>里说要换用bottle,已经过去快两个月了--事实上在那之前我已经開始着手在换了.眼下那个用于 Backbone.js 介绍的样例程序已 ...

  4. 关于sqlmap的两个小坑

    i春秋作家:__LSA__ 0x00 概述 近日在利用sqlmap注入测试时遇到一个奇怪的现象,高版本sqlmap无法检测出注入,但是低版本的可以测出注入,并且能跑出数据不是误报,经过对比测试和查看s ...

  5. for-loop 与 json.Unmarshal 性能分析概要

    原文地址:for-loop 与 json.Unmarshal 性能分析概要 前言 在项目中,常常会遇到循环交换赋值的数据处理场景,尤其是 RPC,数据交互格式要转为 Protobuf,赋值是无法避免的 ...

  6. mciSendString 的两个小坑

    刚刚修正了自己用的小闹钟的代码. 坑1:REPEAT 选项的作用范围 原来用得好好的,之后选择 .wav 文件,居然不出声音了…… 诶,MCI 肯定支持 .wav 的啊…… 仔细想想,我以前都是选 . ...

  7. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  8. C#中的Infinity有个小坑

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天家里有事,上网也不方便,就没有推送文章.今天很累,也不长篇大论了.简单介绍一下最近遇到的 ...

  9. 使用EMMET中的小坑

    使用EMMET写HTML的时候,是一个非常爽的事情.但是今天我使用时,发现一个小坑.以前倒也没有注意,不过需要非常的小心. form[action="/process" metho ...

随机推荐

  1. 【php】 jsonp转数组函数jsonp_decode

    分享一个可以跟json一样用的函数jsonp_decode,能把jsonp格式数据转为php数组或对象. /**  * 把jsonp转为php数组  * @param string $jsonp js ...

  2. Spting:基于注解的组件化管理

    @Component,@Controller(控制层),@Service(业务层),@Repository(持久层) 以上四个注解的功能完全相同,不过在实际开发中,要在不同功能的类上加上响应的注解 1 ...

  3. virtualbox 基于nat模式搭建局域网并且和宿主机通信

    1.VIRTUALbox 2.两台虚拟机,设置网络为DHCP方式 检查文件确认是dhcp模式不是的百度搜索修改:/etc/sysconfig/network-scripts/ifcfg-enps3(网 ...

  4. C#数据结构与算法系列(二):稀疏数组(SparseArray)

    1.介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组.    稀疏数组的处理方法是: 1.记录数组一共有几行几列,有多少个不同的值    2.把具有不同值的元素的 ...

  5. 在CentOS下利用Docker一键安装seafile

    https://cloud.seafile.com/published/seafile-manual-cn/docker/pro-edition/%E7%94%A8Docker%E9%83%A8%E7 ...

  6. CVE-2020-0796—远程代码执行漏洞

    一.漏洞名称: 微软SMBv3 Client/Server - 远程代码执行漏洞——CVE-2020-0796 二.识别点: 445端口 三.影响范围: Windows 10 Version 1903 ...

  7. springboot 配置本地文件映射路径

    @Configuration public class MyBlogWebMvcConfigurer extends WebMvcConfigurerAdapter { @Autowired priv ...

  8. [bzoj1690] [Usaco2007 Dec] 奶牛的旅行 (最大比率环)

    题目 作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天.旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇. 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了 ...

  9. 09.DRF-ModelSerializer

    四.模型类序列化器ModelSerializer 如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serial ...

  10. Nginx 如何自定义变量?

    之前的两篇文章 Nginx 变量介绍以及利用 Nginx 变量做防盗链 讲的是 Nginx 有哪些变量以及一个常见的应用.那么如此灵活的 Nginx 怎么能不支持自定义变量呢,今天的文章就来说一下自定 ...