总览
JSON是最流行的序列化格式之一。 它是人类可读的,相当简洁的,任何Web应用程序都可以使用JavaScript轻松地对其进行解析。 Go作为一种现代编程语言,在其标准库中对JSON序列化提供了一流的支持。
但是这里有些角落和缝隙。 在本教程中,您将学习如何有效地对JSON以及从JSON序列化和反序列化任意数据和结构化数据。 您还将学习如何处理高级场景,例如序列化枚举。
json包
Go在其标准库的编码包中支持多种序列化格式。 其中之一是流行的JSON格式。 您可以使用Marshal()函数将Golang值序列化为一个字节片。 您可以使用Unmarshal()函数将字节的片段反序列化为Golang值。 就这么简单。 在本文的上下文中,以下术语是等效的:
- 序列化/编码/编组
- 反序列化/解码/解组
我更喜欢序列化,因为它反映了以下事实:您将潜在的分层数据结构与字节流进行了相互转换。
元帅
Marshal()函数可以接受任何内容,这在Go中表示空接口,并返回一片字节和错误。 这是签名:
func Marshal(v interface{}) ([]byte, error)
如果Marshal()无法序列化输入值,它将返回非nil错误。 Marshal()有一些严格的限制(我们将在后面看到如何使用自定义编组器克服它们):
- 映射键必须是字符串。
- 映射值必须是json包可序列化的类型。
- 不支持以下类型:通道,复杂和功能。
- 不支持循环数据结构。
- 指针将被编码(然后解码)为指针所指向的值(如果指针为nil,则为“ null”)。
元帅
Unmarshal()函数采用一个字节片,该字节片有望表示有效的JSON和目标接口,该接口通常是指向结构或基本类型的指针。 它以通用方式将JSON反序列化到接口中。 如果序列化失败,它将返回错误。 这是签名:
func Unmarshal(data []byte, v interface{}) error
序列化简单类型
您可以轻松地序列化简单类型,例如使用json包。 结果将不是完整的JSON对象,而是一个简单的字符串。 在这里,int 5被序列化为字节数组[53],它对应于字符串“ 5”。
// Serialize int
var x = 5
bytes, err := json.Marshal(x)
if err != nil {
fmt.Println("Can't serislize", x)
}
fmt.Printf("%v => %v, '%v'\n", x, bytes, string(bytes))
// Deserialize int
var r int
err = json.Unmarshal(bytes, &r)
if err != nil {
fmt.Println("Can't deserislize", bytes)
}
fmt.Printf("%v => %v\n", bytes, r)
Output:
- 5 => [53], '5'
- [53] => 5
如果尝试序列化不支持的类型(如函数),则会收到错误消息:
// Trying to serialize a function
foo := func() {
fmt.Println("foo() here")
}
bytes, err = json.Marshal(foo)
if err != nil {
fmt.Println(err)
}
Output:
json: unsupported type: func()
使用地图序列化任意数据
JSON的强大之处在于它可以很好地表示任意分层数据。 JSON包支持它,并利用通用的空接口(interface {})表示任何JSON层次结构。 这是反序列化并随后序列化二叉树的示例,其中每个节点都有一个int值以及左右两个分支,其中可能包含另一个节点或为null。
JSON空值等于Go nil。 从输出中可以看到, json.Unmarshal()
函数成功地将JSON blob转换为Go数据结构,该数据结构由嵌套的接口映射组成,并将值类型保留为int。 json.Marshal()
函数成功地将所得嵌套对象序列化为相同的JSON表示形式。
// Arbitrary nested JSON
dd := `
{
"valu