Go json反序列化“null“的问题解决
作者:NJU_lemon 发布时间:2024-02-18 22:54:19
有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进这个map
func mergeContent(inputJson string, inputMap map[string]interface{}) (map[string]interface{}, error) {
jsonMap := make(map[string]interface{})
if inputJson != "" {
decoder := jsoniter.NewDecoder(strings.NewReader(inputJson))
decoder.UseNumber()
if err := decoder.Decode(&jsonMap); err != nil {
return nil, err
}
}
//merge
for k, v := range inputMap {
jsonMap[k] = v
}
return jsonMap, nil
}
看上去是不是一段很健康的代码?
结合标题再看看呢?
如果输入的json字符串是"null"会发生什么呢?
实验
func main(){
inputMap := make(map[string]interface{})
inputMap["test"] = 1
outputMap, err := mergeContent("null", inputMap)
if err != nil {
fmt.Println("err:", err)
return
}
fmt.Printf("output:%+v\n", outputMap)
}
不出意外的话,要出意外了
它说我给一个nil map赋值了,但我明明在反序列化之前给jsonMap初始化了的,原来,jsoniter这个库【其他库没测】在进行json序列化
时,会把nil
【即指针类型(比如slice、map和*T)的未初始化时的形态】序列化为字符串"null",反序列化
时会把字符串"null"
,如果目标类型是指针类型,则会反序列化为nil
其他测试
知道现象和原因之后,我又测试了些其他的东西
需要注意的是fmt很多时候打印nil的指针类型时不会输出nil,比如nil的slice和map,会打印成[]和map[]
;
package main
import (
"fmt"
jsoniter "github.com/json-iterator/go"
)
type Marshaler struct {
A map[string]interface{}
B []string
C [10]int
D *string
E *EE
F string
g string
}
type EE struct {
EEE []string
}
func main() {
mal := Marshaler{
E: &EE{},
}
mal1 := &Marshaler{}
e1 := &EE{}
e2 := EE{EEE: []string{}}
var t1 *string
var t2 []int
var t3 map[string]interface{}
var t4 = make([]string, 0)
res1, _ := jsoniter.MarshalToString(mal)
res2, _ := jsoniter.MarshalToString(mal1)
res3, _ := jsoniter.MarshalToString(e1)
res4, _ := jsoniter.MarshalToString(e2)
res5, _ := jsoniter.MarshalToString(t1)
res6, _ := jsoniter.MarshalToString(t2)
res7, _ := jsoniter.MarshalToString(t3)
res8, _ := jsoniter.MarshalToString(t4)
fmt.Printf("res1: %+v\n", res1)
fmt.Printf("res2: %+v\n", res2)
fmt.Printf("res3: %+v\n", res3)
fmt.Printf("res4: %+v\n", res4)
fmt.Printf("res5: %+v\n", res5)
fmt.Printf("res6: %+v\n", res6)
fmt.Printf("res7: %+v\n", res7)
fmt.Printf("res8: %+v\n", res8)
params := make(map[string]interface{})
if err := jsoniter.Unmarshal([]byte(res6), ¶ms); err != nil {
fmt.Println("null Unmarshal err:", err)
} else {
fmt.Printf("null Unmarshal map: %+v\n", params)
}
if err := jsoniter.Unmarshal([]byte(res6), &mal); err != nil {
fmt.Println("null Unmarshal err:", err)
} else {
fmt.Printf("null Unmarshal Marshaler: %+v\n", mal)
}
if err := jsoniter.Unmarshal([]byte(res6), &mal1); err != nil {
fmt.Println("null Unmarshal err:", err)
} else {
fmt.Printf("null Unmarshal Marshaler: %+v\n", mal1)
}
if err := jsoniter.Unmarshal([]byte(res6), &t4); err != nil {
fmt.Println("null Unmarshal err:", err)
} else {
fmt.Printf("null Unmarshal []string: %+v\n", t4)
fmt.Println(t4 == nil)
}
}
输出:
res1: {"A":null,"B":null,"C":[0,0,0,0,0,0,0,0,0,0],"D":null,"E":{"EEE":null},"F"
:""}
res2: {"A":null,"B":null,"C":[0,0,0,0,0,0,0,0,0,0],"D":null,"E":null,"F":""}
res3: {"EEE":null}
res4: {"EEE":[]}
res5: null
res6: null
res7: null
res8: []
//下面的打印不够准确,看debug截图
null Unmarshal map: map[]
null Unmarshal Marshaler: {A:map[] B:[] C:[0 0 0 0 0 0 0 0 0 0] D:<nil> E:0xc000
004510 F: g:}
null Unmarshal Marshaler: <nil>
null Unmarshal []string: []
true
补充说明
默认的反序列化是用float64来接数字类型的,原来的数字太大会出现精度丢失问题
"null"用int或float32等基础数字类型来接会变成默认值0
很多json库在反序列化时都会存在精度丢失问题,比如int64的最后几位变成0,是因为不明确json字符串代表的struct的场景下,用map[string]interface{}来接反序列化之后的内容,会默认用float64来接数字类型,“int64是将64bit的数据全部用来存储数据,但是float64需要表达的信息更多,因此float64单纯用于数据存储的位数将小于64bit,这就导致了float64可存储的最大整数是小于int64的。”,理论上数值超过9007199254740991就可能会出现精度缺失,反序列化时需要针对数字类型单独处理【用struct来接,并且保证类型能对应上就不会有以上问题】:
来源:https://blog.csdn.net/qq_39618369/article/details/129478386


猜你喜欢
- 在使用Ajax过程中,有时候总会遇到一些难题,浏览器兼容、编码、IE下的特殊处理等等,偶尔会搞的人头昏脑胀哭笑不得,这里列一些小贴士,或许有
- 一、网络爬虫网络爬虫又被称为网络蜘蛛(🕷️),我们可以把互联网想象成一个蜘蛛网,每一个网站都是一个节点,我们可以使用一只蜘蛛去各个网页抓取我
- 周末在家,儿子闹着要玩游戏,让玩吧,不利于健康,不让玩吧,扛不住他折腾,于是想,不如一起搞个小游戏玩玩!之前给他编过猜数字 和 掷骰子 游戏
- 下面发一个简单的在线调试服务端js代码的asp源码。并可以提示代码具体错误信息。<%@language="javascrip
- 表的创建CREATE TABLE `lee` (`id` int(10) NOT NULL AUTO_INCREMENT, `name` c
- 实例如下所示:import matplotlib.pyplot as pltplt.imshow(img)#控制台打印出图像对象的信息,而图
- 下载包地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysql-python该页面下找到需要
- post, put请求的参数有两种形式一种是把参数拼接在url中 对应postman第二种是把参数放在body中 对应postman在Pyt
- js阻止浏览器默认行为的简单实例<!DOCTYPE html><html> <head> &
- 数据库(database)MySQL 是最流行的开源数据库系统,可运行于几乎所有的操作系统平台。在《MySQL 安装》一文中详解介绍了安装步
- 一、模拟登录图书馆管理系统我们可以先看一下登录页面(很多学校这些管理系统页面就是很low):两种方式去模拟登录图书馆:1. 构造登录表单进行
- 写在前面和小伙伴们分享一些Python 网络编程的一些笔记,博文为《Python Cookbook》读书后笔记整理博文涉及内容包括:TCP/
- 一、获取安装包最近的版本为0.4.12,下载地址:http://sourceforge.net/projects/sysbench/二、编译
- 在上篇文章中,讲解了MongoDB的基本操作,包括增、删、改、查,但是这些操作都是在命令行模式下进行的,这篇文章中讲解如何使用C#程序连接到
- 例如:select (a+b) as c from 表 类型也一致都是varchar型的,可就是显示不正确。 直到concat() MySQ
- 今天工作中遇到,拿出来说说。网上CSS下拉菜单不少,不过都存在这样那样的问题,主要问题是,如果你菜单下面有一个FLASH的话,很多都会被FL
- Pytest-sugar是一款用来改善控制台显示的插件,增加了进度条显示,使得在用例执行过程中可以看到进度条,而且进度条是根据用例是否通过标
- 前言Tensorflow的核心与NumPy非常相似,但具有GPU支持;Tensorflow支持分布式计算(跨多个设备和服务器)。像NumPy
- 首先为什么会有axis这个概念?因为在numpy模块中,大多数处理的是矩阵或者多维数组,同时,对多维数组或者矩阵的操作有多种可能,为了帮助实
- RNN(recurrent neural Network)循环神经网络主要用于自然语言处理(nature language processi