广告位联系
返回顶部
分享到

Go json反序列化“null“的问题解决

Golang 来源:互联网 作者:佚名 发布时间:2024-02-12 23:03:16 人浏览
摘要

有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进这个map

有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进这个map

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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"会发生什么呢?

 

实验

1

2

3

4

5

6

7

8

9

10

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 ", outputMap)

}

不出意外的话,要出意外了

它说我给一个nil map赋值了,但我明明在反序列化之前给jsonMap初始化了的,原来,jsoniter这个库【其他库没测】在进行json序列化时,会把nil【即指针类型(比如slice、map和*T)的未初始化时的形态】序列化为字符串"null",反序列化时会把字符串"null",如果目标类型是指针类型,则会反序列化为nil

 

其他测试

知道现象和原因之后,我又测试了些其他的东西
需要注意的是fmt很多时候打印nil的指针类型时不会输出nil,比如nil的slice和map,会打印成[]和map[];

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

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 ", res1)

   fmt.Printf("res2: %+v ", res2)

   fmt.Printf("res3: %+v ", res3)

   fmt.Printf("res4: %+v ", res4)

   fmt.Printf("res5: %+v ", res5)

   fmt.Printf("res6: %+v ", res6)

   fmt.Printf("res7: %+v ", res7)

   fmt.Printf("res8: %+v ", 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 ", params)

   }

 

   if err := jsoniter.Unmarshal([]byte(res6), &mal); err != nil {

      fmt.Println("null Unmarshal err:", err)

   } else {

      fmt.Printf("null Unmarshal Marshaler: %+v ", mal)

   }

 

   if err := jsoniter.Unmarshal([]byte(res6), &mal1); err != nil {

      fmt.Println("null Unmarshal err:", err)

   } else {

      fmt.Printf("null Unmarshal Marshaler: %+v ", mal1)

   }

 

   if err := jsoniter.Unmarshal([]byte(res6), &t4); err != nil {

      fmt.Println("null Unmarshal err:", err)

   } else {

      fmt.Printf("null Unmarshal []string: %+v ", 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: E:0xc000
004510 F: g:}
null Unmarshal Marshaler:
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来接,并且保证类型能对应上就不会有以上问题】:


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • go-python库使用应用介绍
    在当今软件开发领域,跨语言编程已经成为一种常见的需求。不同的编程语言各自有其优势和适用场景,因此在项目开发过程中,经常需要
  • Go json反序列化“null“的问题解决

    Go json反序列化“null“的问题解决
    有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进这个map
  • 在golang中将“2023年4月”解析为time.Time对象的详细
    我无法将像April 2023这样的日期字符串解析为 time.Time 对象来比较 golang 中的日期时间对象。 正确答案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main
  • 在golang中,我可以使用flag包来定义一个可以选择
    我想做的是能够运行这三个场景: cmd --test --branchrelease cmd --测试全部 --branch release cmd --分支发布 能够在没有参数(如布尔值)的情况下自行
  • Docker golang + ffmpeg执行命令失败
    您好,我正在使用以下 docker 映像: 1 from golang:alpine3.18 使用 ffmpeg:(可能在这里我遗漏了一些东西) 1 run apk add --no-cache ffmpeg 但是当尝试执
  • 如何使用beego orm在postgres中存储图片
    Postgres如何存储文件 postgres提供了两种不同的方式存储二进制,要么是使用bytea类型直接存储二进制,要么就是使用postgres的LargeObject功能;决
  • GoLang sync.Pool简介与用法
    一句话总结:保存和复用临时对象,减少内存分配,降低GC压力 sync.Pool是可伸缩的,也是并发安全的,其大小仅受限于内存大小。sync.Pool用
  • golang与pgsql交互的实现介绍

    golang与pgsql交互的实现介绍
    1、目的 通过读取配置文件获取pgsql用户名和密码及数据库和数据表,从而读取所需字段值。 2、代码架构 config/config.go:读取配置文件信息
  • Go语言中rune方法使用介绍

    Go语言中rune方法使用介绍
    1.byte类型 byte类型是uint8的别名,表示一个字节, 2.rune类型 rune类型是Go语言中的一个基本类型,其实就是一个int32的别名,主要用于表示一个
  • Go打包附件内容到执行文件的方法
    如果我们的应用在启动的时候需要对数据库进行初始化(比如建表等), 可以通过读取.sql文件内容直接执行. 但是, 这样会带出一个问题: 在发送
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计