JSON 序列化 丨 青训营笔记

106 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记

概述

JSON(JavaScript Object Notation)是一种简单的数据交换格式。在语法上它类似于 JavaScript 的对象和列表。它最常用于 Web 后端和在浏览器中运行的 JavaScript 程序之间的通信,但它也用于许多其他地方。

使用 json package 包,可以轻松地从 Go 程序中读取和写入 JSON 数据。

序列化

Go 中使用 json.Marshal() 序列化数据结构成 JSON字符串:

  • func Marshal(v interface{}) ([]byte, error)

下面给出一个Message结构体并且实例化该结构体:

 type Message struct {
     Name string
     Body string
     Time int64
 }
 ​
 m := Message{"Alice", "Hello", 1294706395881547000}

使用 json.Marshal 序列化这个m:

 b, err := json.Marshal(m)

如果一切顺利,err 将为 nil,b 将是包含此 JSON 数据的 []byte :

 b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)

只有可以表示为有效 JSON 的数据结构才会被序列化:

  • JSON 对象只支持字符串作为键;要对 Go 地图类型进行序列化,它必须采用 map[string]T 的形式(其中 T 是 json 包支持的任何 Go 类型)
  • Channel、complex 和函数类型无法序列化
  • 不支持循环数据结构;它们将导致 Marshal 进入无限循环
  • 指针将被序列化为它们指向的值(如果指针为 nil,则为 “null”)

反序列化

Go 中使用 json.Unmarshal() 反序列化 JSON字符串 成对应的数据结构:

  • func Unmarshal(data []byte, v interface{}) error

首先必须创建一个存储反序列化数据的地方:

 var m Message

然后调用 json.Unmarshal,将 JSON 数据的 []byte 和指向 m 的指针传递给它

 err := json.Unmarshal(b, &m)

如果 b 包含适合 m 的有效 JSON(反序列化成功),则在调用后 err 将为 nil 并且来自 b 的数据将存储在 struct m 中,就像通过如下赋值:

 m = Message{
     Name: "Alice",
     Body: "Hello",
     Time: 1294706395881547000,
 }

当 JSON 数据的结构与 Go 类型不完全匹配时会发生什么?

 b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
 var m Message
 err := json.Unmarshal(b, &m)

Unmarshal 将仅反序列化它可以在目标类型中找到的字段。在这种情况下,只会填充 m 的 Name 字段,而忽略 Food 字段。

当希望从大型 JSON blob(大对象) 中仅选择几个特定字段时,此行为特别有用。这也意味着目标结构中任何未导出的字段都不会受到 Unmarshal 的影响。

但是,如果您事先不知道 JSON 数据的结构怎么办?

使用 带接口的通用 JSON,具体查看官方文档:go.dev/blog/json

序列化与反序列化的简单示例

 package main
 ​
 import (
     "encoding/json"
     "fmt"
 )
 ​
 type Result struct {
     Code    int    `json:"code"`
     Message string `json:"message"`
 }
 ​
 func main() {
     var res Result
     res.Code = 200
     res.Message = "success"
 ​
     // 序列化
     // Marshal 成功时 errs为nil(错误为空)
     jsons, errs := json.Marshal(res)
 ​
     if errs != nil { // 序列化失败
         fmt.Println("json marshal error: ", errs)
     }
 ​
     // jsons 是[]byte类型,转化成string类型便于查看
     fmt.Println("json data: ", string(jsons))
 ​
     // 反序列化
     var res2 Result
     // Unmarshal的第一个参数是json字符串,第二个参数是接受json解析的数据结构
     // 第二个参数必须是指针,否则无法接收解析的数据
     errs = json.Unmarshal(jsons, &res2)
 ​
     if errs != nil { // 反序列化失败
         fmt.Println("json unmarshal error: ", errs)
     }
 ​
     fmt.Println("res2: ", res2)
 }

运行结果:

 json data:  {"code":200,"message":"success"}
 res2:  {200 success}