go原生json(一)
处理json数据是绝大多数程序员都熟悉的操作,很多语言都提供了对json数据的转化和从json中恢复对象的功能(即序列化和反序列化)。go语言也不例外,go原生的encoding/json
库提供了相当强大的功能,可以非常简单地处理序列化和反序列化。
1 json.Marshal()和json.Unmarshal()函数
使用encoding/json
库的Marshal()
和Unmarshal()
函数能够轻松地将go的结构体序列化成二进制格式的json数据,以及把json格式的数据反序列化到结构体中。
示例1:
package main
import (
"encoding/json"
"fmt"
)
// 结构体的成员变量必须以大写字母开头才能被序列化成json
type Employee struct {
ID int
Name string
Email string
}
func main() {
employee1 := Employee{1001, "Bob", "xyz@abc.com"}
// 序列化
jsonData, err := json.Marshal(employee1)
if err != nil {
fmt.Println("serializes failed.")
}
// 默认序列化后是二进制的字节数组
fmt.Println(jsonData)
// output: [123 34 73 68 34 58 49 48 48 49 44 34 78 97 109 101 34 58 34 66 111 98 34 44 34 69 109 97 105 108 34 58 34 120 121 122 64 97 98 99 46 99 111 109 34 125]
fmt.Println(string(jsonData))
// output: {"ID":1001,"Name":"Bob","Email":"xyz@abc.com"}
// 反序列化
var employee2 Employee
err = json.Unmarshal(jsonData, &employee2)
if err != nil {
fmt.Println("deserializes failed.")
}
fmt.Println(employee2)
// output: {1001 Bob xyz@abc.com}
}
使用前需通过import关键字导入encoding/json
库,使用json.Marshal()
序列化结构体时需要注意,结构体的成员变量必须是以大写字母开头(go用首字母大小写表示函数、变量、结构体等是公有的还是私有的,如果是首字母小写的变量,即为私有变量,不能被序列化到json数据中),并且函数返回的是一个字节数组。
使用json.Unmarshal()
函数反序列化时,要注意传入的json数据是字节数组,并且传入json对应的结构体类型的变量,把json数据赋值给该结构体变量。
2 json.MarshalIndent()函数
在第一个示例中,使用string()
函数把序列化后的字节数组转换成string,打印输出的结果是一行。示例中的结构体成员域比较简单,所以显示在一行中看起来没有太糟糕,但是当序列化一个较复杂的结构体并输出后,这样看是非常不方便的,于是encoding/json
库提供了一个MarshalIndent()
函数来格式化输出。
jsonData, err := json.MarshalIndent(employee1, "", " ")
使用这行代码替换示例1中的json.Marshal(),第二个参数表示前缀,暂时不需要,提供一个零值,第三个参数为缩进,这里用两个空格进行缩进,这样得到的json数据就非常清晰了。
3 对未知结构的json数据进行反序列化
示例1中对Employee结构体类型的数据进行反序列化,我们需要先构造一个对应的结构体变量,用于接收json数据的每一个字段值。
实际场景中,我们可能会遇到一些未知结构或不确定结构的json数据,但是又需要该数据中的某些字段。json.Unmarshal()
函数的第二个参数实际上是一个KV格式的数据类型(map[string]interface{}
)。当我们不清楚json数据的结构时,直接声明一个map[string]interface{}类型的变量,可以接收任意结构的json数据。
示例2:
package main
import (
"encoding/json"
"fmt"
)
var employee = `{
"ID": 1001,
"Name": "Bob",
"Age":"28",
"Email": "xyz@abc.com",
"Position":"programmer"
}`
func main() {
// 对未知结构的json数据进行反序列化
var m map[string]interface{}
err := json.Unmarshal([]byte(employee), &m)
if err != nil {
fmt.Println("deserializes failed.")
}
fmt.Println(m)
// output: map[Age:28 Email:xyz@abc.com ID:1001 Name:Bob Position:programmer]
}
上述示例有一个json数据,不同于示例1,该结构多了员工的年龄和职位,显然不能使用Employee结构体接收这个json。可以使用map[string]interface{}
类型的变量获取json的字段值。由于是map类型的KV(hash),字段的顺序可能会发生变化。