一. Go 标准库 json
- Go 标准库中提供了内置的 JSON 编码和解码功能,可以用于序列化和反序列化 JSON 数据
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Phone string `json:"phone"`
}
func main() {
// 创建一个 Person 实例
p := Person{Name: "Tom", Age: 23, Phone: "12345678901"}
// 使用 json 包中的 Marshal 函数进行序列化
data, err := json.Marshal(p)
if err != nil {
fmt.Println("序列化失败:", err)
}
// 完成序列化后打印出得到的 JSON 字符串
fmt.Println(string(data))
// 模拟从网络中读取到的 JSON 字符串
data := `{"name":"Tom","age":23,"phone":"12345678901"}`
// 使用 json 包中的 Unmarshal 函数进行反序列化
var p Person
err := json.Unmarshal([]byte(data), &p)
if err != nil {
fmt.Println("反序列化失败:", err)
}
// 完成反序列化后打印出得到的 Go 结构体对象
fmt.Println(p)
}
- 一些其它功能
//1.格式化输出 JSON 字符串
func test1() {
p := Person{Name: "Tom", Age: 23}
//第二个参数(空字符串)指定了缩进的前缀,而第三个参数(两个空格)指定了每行缩进的内容
data, err := json.MarshalIndent(p, "", " ")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
}
//2.处理不定层数的 JSON 数据
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
//它的类型为 json.RawMessage
ExtraData json.RawMessage `json:"extra_data"`
}
func test2() {
//定义JSON 字符串其中 extra_data 字段的值是一个嵌套结构
data := `
{
"name": "Tom",
"age": 23,
"extra_data": {
"hobby": ["reading", "music"],
"address": {
"city": "Shanghai",
"street": "Nanjing Road"
}
}
}
`
var p Person
err := json.Unmarshal([]byte(data), &p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p.Name, p.Age)
// 处理 extra_data 字段的数据
//先将 extra_data 解析成 json.RawMessage 类型,
var extraData map[string]interface{}
//然后使用 json.Unmarshal 函数再继续解析其它内容
err = json.Unmarshal(p.ExtraData, &extraData)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(extraData["hobby"])
fmt.Println(extraData["address"].(map[string]interface{})["city"])
}
//3.自定义 JSON 序列化器,MarshalJSON 函数
func (p Person) MarshalJSON() ([]byte, error) {
type alias Person
return json.Marshal(&struct {
//在自定义序列化器中创建了一个别名类型 alias,并将其作为新结构体实例的匿名字段
*alias
AgeStr string `json:"age_str"`
}{
alias: (*alias)(&p),
AgeStr: fmt.Sprintf("%d years old", p.Age),
})
}
//序列化时结果中新增了一个 age_str 字段,它的值是 Age 字段的字符串形式附加 " years old" 后缀
func main() {
p := Person{Name: "Tom", Age: 23}
data, err := json.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
data2, err := json.MarshalIndent(p, "", " ")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data2))
}
二. EasJson
- Go 标准库中内置的 JSON底层是基于反射实现的,性能较低,推荐使用"github.com/mailru/easyjson"
package main
import (
"fmt"
//1.导入依赖
"github.com/mailru/easyjson"
)
//2.使用 easyjson 标记指定结构体,结构体上方必须要加上"//go:generate"
//并且要执行"go generate"指令,生成的相关代码会被保存在 person_easyjson.go 文件中,如下:
//go:generate easyjson -all person.go
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
//使用示例
func main() {
p := Person{Name: "Tom", Age: 23}
// 将 Person 实例序列化为 JSON 字节数组
data, err := p.MarshalJSON()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
// 将 JSON 字节数组反序列化为 Person 实例
var p2 Person
err = p2.UnmarshalJSON(data)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", p2)
jsonString := `{"name":"Tom","age":23,"address":{"city":"Shanghai","country":"China"}}`
// 将 JSON 字符串反序列化为 map 类型的数据
var data map[string]interface{}
err := easyjson.Unmarshal([]byte(jsonString), &data)
if err != nil {
fmt.Println(err)
return
}
}
- 序列化时忽略空值通过omitempty标签
type Person struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
}
func main() {
p := Person{Name: "Tom"}
// 将 Person 实例序列化为 JSON 字节数组,忽略空值字段
data, err := easyjson.MarshalWithOptions(&p, easyjson.MarshalOptions{
UseConstKey: true,
Indent: "",
UnescapeHTML:true,
OmitEmpty: true,
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
}
- 自定义序列化和反序列化方法
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func (p *Person) UnmarshalJSON(data []byte) error {
type Alias Person
aux := &struct {
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
p.Name = strings.ToUpper(p.Name)
return nil
}
func (p *Person) MarshalJSON() ([]byte, error) {
type Alias Person
return json.Marshal(&struct {
*Alias
Name string `json:"name"`
}{
Alias: (*Alias)(p),
Name: strings.ToLower(p.Name),
})
}
func main() {
p := &Person{Name: "Tom", Age: 23}
data, err := easyjson.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
p2 := &Person{}
err = easyjson.Unmarshal(data, p2)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", p2)
}
- 支持 slice 和 map 类型的 JSON 序列化和反序列化
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
people := []Person{
{Name: "Tom", Age: 23},
{Name: "Jerry", Age: 25},
}
// 将 slice 序列化为 JSON 字节数组
data, err := easyjson.Marshal(people)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
// 将 JSON 字节数组反序列化为 slice
var people2 []Person
err = easyjson.Unmarshal(data, &people2)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", people2)
}
- easyjson 库在序列化和反序列化时采用对象池技术来减少内存分配次数,从而提升程序性能
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := &Person{Name:"Tom", Age:23}
data, err := easyjson.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
var p2 Person
//easyjson.NewDecoder 创建一个解码器对象
decoder := easyjson.NewDecoder(bytes.NewReader(data))
for i := 0; i < 10000; i++ {
err = decoder.Decode(&p2)
if err != nil {
fmt.Println(err)
return
}
// 使用解析结果...
}
}