脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Golang实现解析JSON的三种方法总结

Golang实现解析JSON的三种方法总结

2022-11-17 12:22Go和分布式IM Golang

这篇文章主要为大家详细介绍了Golang实现解析JSON的三种方法,文中的示例代码讲解详细,对我们学习了解JSON有一定帮助,需要的可以参考一下

背景

这是一篇写给0-1年新人的文章,短平快的教会你如何解析json字符串。

示例Json

假设有如下json字符串:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
   "userName":"admin",
   "nick_name":"管理员",
   "info":{
      "age":18
   },
   "extra":[
      {
         "address":"上海市"
      },
      {
         "address":"北京市"
      }
   ]
}

我们来看看,如何在go中解析。

例子

直接上代码:

?
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
package main
  
import (
    "encoding/json"
    "log"
    "github.com/tidwall/gjson"
)
  
// 嵌套一个对象
type Info struct {
    Age int `json:"age"`
}
  
var info = Info{Age: 12}
  
// 嵌套一个对象数组
type Extra struct {
    Address string `json:"address"`
}
  
// 定义需要反序列化的结构体
type UserRequest struct {
    Name     string  `json:"userName"// 通过tag里面的json,来指定json字符串中该字段的值从那里解析,不需要和字段名一样
    NickName string  `json:"nick_name"` // 如果没对应上,解析不了
    info     Info    `json:"info"`      // 小写私有的,故反序列化失效,该字段永远为空
    Extra    []Extra `json:"extra"`
}
  
func main() {
    jsonStr := `
    {
        "userName":"admin",
        "nick_name":"管理员",
        "info":{
           "age":18
        },
        "extra":[
           {
              "address":"上海市"
           },
           {
              "address":"北京市"
           }
        ]
     }`
  
    // 方式一:序列化成map,经常使用
    anyMap := make(map[string]interface{}, 0)
    if err := json.Unmarshal([]byte(jsonStr), &anyMap); err != nil {
        panic(err)
    }
    log.Println("Unmarshal to map result:", anyMap)
  
    // 方式二:反序列化成对象,经常使用
    req := UserRequest{}
    if err := json.Unmarshal([]byte(jsonStr), &req); err != nil {
        panic(err)
    }
    log.Println("Unmarshal to struct:", req)
  
    // 方式三:不反序列化,只读取单个key,经常使用。适合特别复杂的json字符串,或者有多种if else结构的场景
    userName := gjson.Get(jsonStr, "userName")
    nickName := gjson.Get(jsonStr, "nick_name")
    age := gjson.Get(jsonStr, "info.age").Int()
  
    // 取得extra数组0位置的对象
    address1 := gjson.Get(jsonStr, "extra").Array()[1]
    log.Println("get raw value by key:", userName, nickName, age, address1.Get("address"))
}

运行后输出:

2022/09/13 11:09:13 Unmarshal to map result: map[extra:[map[address:上海市] map[address:北京市]] info:map[age:18] nick_name:管理员 userName:admin]
2022/09/13 11:09:13 Unmarshal to struct: {admin 管理员 {0} [{上海市} {北京市}]}
2022/09/13 11:09:13 get raw value by key: admin 管理员 18 北京市

解释

1)反序列化成map

?
1
2
3
anyMap := make(map[string]interface{}, 0)
if err := json.Unmarshal([]byte(jsonStr), &anyMap);
//...

我们看到,key是string,value是interface{},所以你取值的时候,需要这样取:

?
1
2
3
4
5
ageVal,ok := anyMap["age"]
if ok{
    age := ageVal.(int)
    log.Println(age)
}

是不是感觉非常麻烦?一是需要判断key是否存在,二是类型转换。

所以,反序列化时这种方式不是很常用,但是序列化的时候,非常方便,用的较多。

比如在gin框架中,就被大量使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type LoginReq struct {
   UserName string `json:"user_name"`
}
  
func onLogin(ctx *gin.Context) {
   req := LoginReq{}
   if err := ctx.BindJSON(&req); err != nil {
      ctx.Error(err)
   }
  
   if req.UserName == "admin" {
      ctx.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success"})
   } else {
      ctx.JSON(http.StatusUnauthorized, gin.H{"code": -1, "msg": "账号错误!"})
   }
}

看到 gin.H 了吗?实际上就是:

?
1
2
// H is a shortcut for map[string]interface{}
type H map[string]interface{}

所以:

?
1
ctx.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success”})

等价于: 

?
1
ctx.JSON(http.StatusOK, map[string]interface{}{"code": 0, "msg": "success"})

这样做的好处是,不需要预先定义结构体,直接通过语法糖实现,代码更简洁。

2)反序列化成对象

这个是最常用的,通过 `json.Unmarshal` 把二进制反序列化成对象,通过 `json.Marshal()` 把对象序列化成json字符串。需要注意的是:

字段tag中的名字要和json字符串中的对应,否则解析不到值

字段名不能是小写开头,私有的字段无法将被忽略,也会解析不到值

支持嵌套,由go标准库通过反射自动完成

3)复杂json的解析

有时候,一个json非常复杂,或者你只需要取某个字段,那么就可以使用这种方式:

?
1
userName := gjson.Get(jsonStr, "userName")

别忘记,gjson 不是标准库的包,需要使用 go get github.com/tidwall/gjson 安装。 

总结

本文介绍了解析json的3种方式:

  • 直接解析成 map[string]interface{}
  • 解析成对象
  • 读取单个key

这3种方式没有好坏之分,只看具体的场景,灵活使用即可。唯一不变的是,都是通过 `json.Unmarshal` 把二进制反序列化成对象,通过 `json.Marshal()` 把对象

序列化成json字符串。

加餐:什么是序列化?

百科中说:序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。

通俗点说就是因为网络只能发送二进制流,而我们代码中的数据又是保存在各种对象中。在C/S(客户端/服务器)架构中,客户端传递数据给服务器势必就要进行2次转换。

客户端:发送之前,要把对象转换为二进制字节流。

服务器:接收到二进制流之后,要转换为对象。

Golang实现解析JSON的三种方法总结

这种从对象到二进制流的过程叫序列化(Serialization),反过来从二进制流转换成对象就叫反序列化。

到此这篇关于Golang实现解析JSON的三种方法总结的文章就介绍到这了,更多相关Golang解析JSON内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/wishFreedom/p/16688734.html

延伸 · 阅读

精彩推荐
  • GolangGo语言七篇入门教程二程序结构与数据类型

    Go语言七篇入门教程二程序结构与数据类型

    这篇文章主要为大家介绍了Go语言的程序结构与数据类型,本篇文章是Go语言七篇入门系列文,有需要的朋友可以借鉴参考下,希望能够有所帮助...

    小生凡一8692021-12-01
  • GolangGo语言实现简单的一个静态WEB服务器

    Go语言实现简单的一个静态WEB服务器

    这篇文章主要介绍了Go语言实现简单的一个静态WEB服务器,本文给出了实现代码和运行效果,学习Golang的练手作品,需要的朋友可以参考下 ...

    junjie7072020-04-10
  • Golanggolang 自旋锁的实现

    golang 自旋锁的实现

    这篇文章主要介绍了golang 自旋锁的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    one_zheng5162020-05-21
  • GolangGo 分布式链路追踪实现原理解析

    Go 分布式链路追踪实现原理解析

    分布式链路追踪作为解决分布式应用可观测问题的重要技术,愈发成为分布式应用不可缺少的基础设施,本文将详细介绍分布式链路的核心概念、架构原理...

    尔达 Erda4112022-10-27
  • Golanggo语言实现sftp包上传文件和文件夹到远程服务器操作

    go语言实现sftp包上传文件和文件夹到远程服务器操作

    这篇文章主要介绍了go语言实现sftp包上传文件和文件夹到远程服务器操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    奔流入海17632021-03-06
  • Golang如何使用 Go 读取和写入 Excel (XLSX) 文件

    如何使用 Go 读取和写入 Excel (XLSX) 文件

    在本文中,我们将解释如何使用 Go 的 Excelize 库读写 Excel (xlsx) 文件并生成图片和图表。...

    DZone10852021-08-02
  • GolangGolang中的godoc使用简介(推荐)

    Golang中的godoc使用简介(推荐)

    Godoc是go语言的文档化工具,类似于文档化工具godoc,类似于Python的Docstring和Java的Javadoc,这篇文章主要介绍了Golang中的godoc使用简介,需要的朋友可以参考下...

    raoxiaoya7052022-10-31
  • GolangGoLand如何设置中文

    GoLand如何设置中文

    这篇文章主要介绍了GoLand如何设置中文,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参...

    正在攀登的小蜗牛25522021-02-21