这是我参与「第三届青训营 -后端场」笔记创作活动的第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}