我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Golang中JSON遇到的坑如何解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Golang中JSON遇到的坑如何解决

本篇内容主要讲解“Golang中JSON遇到的坑如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中JSON遇到的坑如何解决”吧!

空指针会被解析成字符串"null"

type Person struct {Name stringAge  int}func main() {var p *Personbytes, err := json.Marshal(p)checkError(err)fmt.Printf("len:%d, result:%s\n", len(bytes), string(bytes))  // len:4, result:null}func checkError(err error) {if err != nil {fmt.Printf("err:%+v\n", err)}}

json.Marshal一个空指针的时候,得到的结果居然是"null"字符串,我以为是""或者报错。

还有个奇怪的坑

type Person struct {Name stringAge  int}func main() {var p *Persons := `null`err := json.Unmarshal([]byte(s), &p)checkError(err)fmt.Printf("p:%+v\n", p) // p:<nil>}

这个居然不报错,而是得到空指针p

如果把s随便换成其他字符串s := "abc",则报错:invalid character 'a' looking for beginning of value,之前我理解的是null对go来说应该跟abc没有差别,都是字符串。没想到他们是不一样的,下面来深究一下json.UnMarshal底层代码。

在UnMarshal之前它有个checkValid函数

func checkValid(data []byte, scan *scanner) error {scan.reset()for _, c := range data {scan.bytes++if scan.step(scan, c) == scanError {return scan.err}}if scan.eof() == scanError {return scan.err}return nil}

checkValid函数会check每一个字符,调用step函数,step初始值是stateBeginValue

// stateBeginValue is the state at the beginning of the input.func stateBeginValue(s *scanner, c byte) int {if isSpace(c) {return scanSkipSpace}switch c {case '{':s.step = stateBeginStringOrEmptyreturn s.pushParseState(c, parseObjectKey, scanBeginObject)case '[':s.step = stateBeginValueOrEmptyreturn s.pushParseState(c, parseArrayValue, scanBeginArray)case '"':s.step = stateInStringreturn scanBeginLiteralcase '-':s.step = stateNegreturn scanBeginLiteralcase '0': // beginning of 0.123s.step = state0return scanBeginLiteralcase 't': // beginning of trues.step = stateTreturn scanBeginLiteralcase 'f': // beginning of falses.step = stateFreturn scanBeginLiteralcase 'n': // beginning of nulls.step = stateNreturn scanBeginLiteral}if '1' <= c && c <= '9' { // beginning of 1234.5s.step = state1return scanBeginLiteral}return s.error(c, "looking for beginning of value")}

有这么一段代码,这是处理第一个字符的,发现它对第一个字符是n有特殊处理并且设置下一个字符处理函数为stateN

// stateN is the state after reading `n`.func stateN(s *scanner, c byte) int {if c == 'u' {s.step = stateNureturn scanContinue}return s.error(c, "in literal null (expecting 'u')")}

也就是下一个字符必须是u,再下一个字符处理函数为stateNu

// stateNu is the state after reading `nu`.func stateNu(s *scanner, c byte) int {if c == 'l' {s.step = stateNulreturn scanContinue}return s.error(c, "in literal null (expecting 'l')")}

也就是下一个字符必须是l,再下一个字符处理函数为stateNul

// stateNul is the state after reading `nul`.func stateNul(s *scanner, c byte) int {if c == 'l' {s.step = stateEndValuereturn scanContinue}return s.error(c, "in literal null (expecting 'l')")}

也就是下一个字符必须是l,再下一个字符处理函数为stateEndValue。

可见checkValid函数对true,false等都有特殊处理。使用时需要注意。

对于json.Marshal函数,通过调试发现它对空指针也有特殊处理

type ptrEncoder struct {elemEnc encoderFunc}func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {if v.IsNil() {e.WriteString("null")return}if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {// We're a large number of nested ptrEncoder.encode calls deep;// start checking if we've run into a pointer cycle.ptr := v.Interface()if _, ok := e.ptrSeen[ptr]; ok {e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})}e.ptrSeen[ptr] = struct{}{}defer delete(e.ptrSeen, ptr)}pe.elemEnc(e, v.Elem(), opts)e.ptrLevel--}

如果是空指针则返回字符串"null",并且不会报错。

int类型会被解析成float64

type Person struct {Name stringAge  int}func main() {p := &Person{Name: "text",Age:  18,}bytes, err := json.Marshal(p)checkError(err)pMap := make(map[string]interface{})err = json.Unmarshal(bytes, &pMap)checkError(err)for k, v := range pMap {fmt.Printf("k:%s,v:%+v, vtype:%v\n", k, v, reflect.TypeOf(v))}}func checkError(err error) {if err != nil {fmt.Printf("err:%+v\n", err)}}

结果

k:Name,v:text, vtype:string
k:Age,v:18, vtype:float64

显然,Age类型变成了float64。会造成什么问题呢?当int大小超过6位的时候就变成了科学计数法 比如Age=1234567, 结果为

k:Name,v:text, vtype:string
k:Age,v:1.234567e+06, vtype:float64

这个时候如果直接将map更新到db,原本是int类型的字段变成了float类型,就报错了

到此,相信大家对“Golang中JSON遇到的坑如何解决”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Golang中JSON遇到的坑如何解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Golang中JSON遇到的坑如何解决

本篇内容主要讲解“Golang中JSON遇到的坑如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中JSON遇到的坑如何解决”吧!空指针会被解析成字符串"null"type Pe
2023-07-05

Golang解析JSON遇到的坑及解决方法

这篇文章主要为大家介绍了Golang解析JSON时会遇到的一些坑及解决方法,文中的示例代码讲解详细,对我们学习Go语言有一点的帮助,需要的可以参考一下
2023-02-26

springboot连接sqllite遇到的坑如何解决

本篇内容主要讲解“springboot连接sqllite遇到的坑如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot连接sqllite遇到的坑如何解决”吧!springbo
2023-07-02

MyBatis+MyBatisPlus中遇到的坑怎么解决

这篇文章主要介绍了MyBatis+MyBatisPlus中遇到的坑怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MyBatis+MyBatisPlus中遇到的坑怎么解决文章都会有所收获,下面我们一起来看
2023-07-05

Feign+mybatisplus搭建项目遇到的坑如何解决

这篇文章主要讲解了“Feign+mybatisplus搭建项目遇到的坑如何解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Feign+mybatisplus搭建项目遇到的坑如何解决”吧!出
2023-07-05

开启Selinux遇到的坑及解决

这篇文章详细介绍了开启SELinux时可能遇到的常见问题和解决办法,包括:selinuxfs未挂载、策略不兼容、更新问题、上下文不正确、布尔值错误配置、审计记录已满、权限拒绝和导致系统无法启动。本文提供了针对每个问题的具体解决方案,包括挂载selinuxfs、检查策略、强制安装更新、设置正确上下文、修改布尔值、增加队列大小、授予权限和禁用SELinux。
开启Selinux遇到的坑及解决
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录