[系列] Go - json.Unmarshal 遇到的小坑
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 遇到的小坑的更多相关文章
- net core 小坑杂记之配置文件读取(不定期更新)
其实很早就想写了,原想等积累差不多了再写的,但是发现遇到一个当时记下效果会比较好,所以就不定期更新这个系列了,后面获取会整个整理一下. 此篇记载net core入门时踩的一些坑,网上教程太少了,也不规 ...
- Vue中应用CORS实现AJAX跨域,及它在 form data 和 request payload 的小坑处理
基本概念部分(一):理解CORS 说道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域资源共享"(Cross-origin resource sharing),它是一个W3 ...
- bottle的几个小坑
距离我在<web.py应用工具库:webpyext>里说要换用bottle,已经过去快两个月了--事实上在那之前我已经開始着手在换了.眼下那个用于 Backbone.js 介绍的样例程序已 ...
- 关于sqlmap的两个小坑
i春秋作家:__LSA__ 0x00 概述 近日在利用sqlmap注入测试时遇到一个奇怪的现象,高版本sqlmap无法检测出注入,但是低版本的可以测出注入,并且能跑出数据不是误报,经过对比测试和查看s ...
- for-loop 与 json.Unmarshal 性能分析概要
原文地址:for-loop 与 json.Unmarshal 性能分析概要 前言 在项目中,常常会遇到循环交换赋值的数据处理场景,尤其是 RPC,数据交互格式要转为 Protobuf,赋值是无法避免的 ...
- mciSendString 的两个小坑
刚刚修正了自己用的小闹钟的代码. 坑1:REPEAT 选项的作用范围 原来用得好好的,之后选择 .wav 文件,居然不出声音了…… 诶,MCI 肯定支持 .wav 的啊…… 仔细想想,我以前都是选 . ...
- 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式
注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...
- C#中的Infinity有个小坑
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天家里有事,上网也不方便,就没有推送文章.今天很累,也不长篇大论了.简单介绍一下最近遇到的 ...
- 使用EMMET中的小坑
使用EMMET写HTML的时候,是一个非常爽的事情.但是今天我使用时,发现一个小坑.以前倒也没有注意,不过需要非常的小心. form[action="/process" metho ...
随机推荐
- fedora gtk+ 2.0环境安装配置
1.安装gtk yum install gtk2 gtk2-devel gtk2-devel-docs 2.测试是否安装成功 pkg-config --cflags --libs gtk+-2.0 执 ...
- react中的ref的3种方式
2020-03-31 react中的ref的3种方式 react中ref的3种绑定方式 方式1: string类型绑定 类似于vue中的ref绑定方式,可以通过this.refs.绑定的ref的名字获 ...
- cubic-bezier() 函数
2020-03-13 cubic-bezier() 函数 ubic-bezier() 函数定义了一个贝塞尔曲线(Cubic Bezier). 贝塞尔曲线曲线由四个点 P0,P1,P2 和 P3 定义. ...
- JPA 中 find() 和 getReference() 的区别
在查询的时候有两个方法:find()和getReference(),这两个方法的参数以及调用方式都相同.那么这两个方法有什么不一样的呢? find()称为 立即加载,顾名思义就是在调用的时候立即执行查 ...
- Python函数&异常处理
1. 函数基础 1.1 参数和返回值 1.1.1 参数 位置参数.关键字参数 def my_func1(x, y, z): print(x+y+z, "计算结束") my_func ...
- Dorado开发——树形下拉框
最近在学习Dorado开发的过程中,遇到了一个问题,Dorado的树形下拉框选择:Dorado默认情况下父节点和子节点都是可选的,而我要实现的是父节点不可选. 解决办法:在下拉框中,判断父子节点,点击 ...
- jmeter录制app测试脚本
1.jmeter 下载地址 https://jmeter.apache.org 2.选择下载包 3.下载完成后解压即可使用(也可以配置环境变量,但我一般不配置,可以使用) 4.打开jmeter 创建线 ...
- Android学习笔记长按事件的处理
常见的长按事件 代码示例: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedIns ...
- 【Spring】Bean的LifeCycle(生命周期)
菜瓜:水稻,上次说Bean的LifeCycle,还没讲完 水稻:啥?说人话? 菜瓜:spring,bean,生命周期 水稻:哦哦,下次直接说人话.说正事,先从BeanFactory.Applicati ...
- 嵌入式QT开发视频教程-供参考
免费嵌入式QT开发视频教程 https://pan.baidu.com/s/1bprhJ2Z QT初级到高级编程视频教程--丁林松.rarhttp://www.jisoupan.com/share/2 ...