在 Go 语言中,操作 JSON 的标准库是 encoding/json,使用 json.Marshal() 方法可以将结构体转换为 JSON 数据,使用 json.Unmarshal() 方法可以将 JSON 数据转换为 Go 语言的结构体。

示例代码如下:

package main

import (
	"encoding/json"
	"fmt"
)

type Book struct {
	Title       string
	Authors     []string
	Publisher   string
	IsPublished bool
	Price       float32
}

func jsonEncode() {
	gobook := Book{
		"Go语言编程",
		[]string{"XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan", "XuDaoli"},
		"ituring.com.cn",
		true,
		9.99,
	}

	// 返回结果 b 是 []byte 类型
	b, err := json.Marshal(gobook)

	if err != nil {
		fmt.Printf("jsonEncode error: %s\n", err)
		return
	}

	fmt.Printf("jsonEncode result: %s\n", b)
}

func jsonDecode() {
	str := `{
		"Title": "Go语言编程",
		"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan", "XuDaoli"],
		"Publisher": "ituring.com.cn",
		"IsPublished": true,
		"Price": 9.99
	}`

	b := []byte(str)

	var gobook Book
	err := json.Unmarshal(b, &gobook)

	if err != nil {
		fmt.Printf("jsonDecode error: %s\n", err)
		return
	}

	fmt.Printf("jsonDecode result: %+v\n", gobook)
}

func main() {
	//转换为json
	jsonEncode()

	//解析json
	jsonDecode()
}

上面的代码运行后输出结果为:

jsonEncode result: {"Title":"Go语言编程","Authors":["XuShiwei","HughLv","Pandaman","GuaguaSong","HanTuo","BertYuan","XuDaoli"],"Publisher":"ituring.com.cn","IsPublished":true,"Price":9.99}
jsonDecode result: {Title:Go语言编程 Authors:[XuShiwei HughLv Pandaman GuaguaSong HanTuo BertYuan XuDaoli] Publisher:ituring.com.cn IsPublished:true Price:9.99}

Go 语言中根据首字母的大小写来确定可以访问的权限,结构体中如果有小写字母开头的属性,转换 JSON 时会被忽略,如:

type Book struct {
	Title       string
	authors     []string  //首字母小写
	publisher   string    //首字母小写
	IsPublished bool
	Price       float32
}

转换为 JSON 的结果为:

{"Title":"Go语言编程","IsPublished":true,"Price":9.99}

把结构体的属性名首字母改成小写,转换成 JSON 后,该属性丢失,反序列化操作同理。因此,在定义结构体的时候,要特别注意。

既然 JSON 作为通用的数据交换格式,那我们不可能要求接口方把所有的 key 都设计为大写字母开头,尤其是在与第三方平台对接的时候。于是,在 Go 语言中,有另外一种解决办法。

在定义结构体的时候,在后面写上与 JSON 对应的 key,如:

type Book struct {
	Title       string   `json:"title"`
	Authors     []string `json:"authors"`
	Publisher   string   `json:"publisher"`
	IsPublished bool     `json:"is_published"`
	Price       float32  `json:"price"`
}

转换为 JSON 后得到:

{"title":"Go语言编程","authors":["XuShiwei","HughLv","Pandaman","GuaguaSong","HanTuo","BertYuan","XuDaoli"],"publisher":"ituring.com.cn","is_published":true,"price":9.99}

同样的,反序列化时,JSON 数据中小写字母开头的 key,也可以转换为 Go 中对应的属性。

有的时候,若所给的 JSON 的结构未知,则我们无法事先定义与之相匹配的结构体。这时,只需将这段 JSON 数据解码输出到一个空接口即可。例如:

func jsonDecode() {
	str := `{
		"Title": "Go语言编程",
		"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan", "XuDaoli"],
		"Publisher": "ituring.com.cn",
		"IsPublished": true,
		"Price": 9.99
	}`

	b := []byte(str)

	// Go 中 interface{} 可表示任意类型
	var r interface{}
	err := json.Unmarshal(b, &r)

	if err != nil {
		fmt.Printf("jsonDecode error: %s\n", err)
		return
	}

	fmt.Printf("jsonDecode result: %+v\n", r)
}

得到的结果 r 是一个 map:

jsonDecode result: map[Authors:[XuShiwei HughLv Pandaman GuaguaSong HanTuo BertYuan XuDaoli] IsPublished:true Price:9.99 Publisher:ituring.com.cn Title:Go语言编程]