JSON 是一种用于收发结构化数据的符号,简明、易读,被广泛应用。

JSON 是对 JavaScript 值(字符串,数字,布尔,数组,对象)的一种编码,编码形式是 Unicode 文本。JSON 的基础类型有数字类型(以小数或科学技术法的形式表示)、布尔类型、字符串类型,基础类型可以用 JSON 数组和对象递归地组合。

The basic JSON types are numbers (in decimal or scientific notation), booleans (true or false), and strings, which are sequences of Unicode code points enclosed in double quotes, with backslash escapes using a similar notation to Go, though JSON’s \Uhhhh numeric escapes denote UTF-16 codes, not runes.

JSON 数组用于编码 Go 数组和切片,JSON 对象用于编码 Go 结构体和 Map。

将 Go 的数据结构转成 JSON 称为 marshaling,通过调用 json.Marshal 实现。Marshal 后得到的是一个不含空格的紧凑的字符串的字节切片,不易读,MarshalIndent 则可以添加缩进。

利用反射机制,Marshal 使用结构体字段名作为 JSON 对象的字段名,只有输出的(exported)字段会被 marshal。

字段标签(field tag)在编译时和结构体字段关联。字段标签可以是任意字符串,通常是空格分隔key:"value" 对,而又因为包含了双引号,所以通常用 raw string literal 形式写。其中名为 json 的键用来控制 encoding/json 包的行为。

type Movie struct {
    Title string
    Year int `json:"released"`
    Color bool `json:"color,omitempty"`
    Actors []string
}
/*
// Field is ignored by this package
{
    Field int `json:"-"`
}

// Field appears in JSON as key "-"
{
    Field int `json:"-,"`
}
*/

json 标签的第一部分用于设置 Go 字段的 JSON 别名(JSON 和 Go 中命名惯例不同);omitempty 选项的作用是 Go 字段是零值或字段不存在,则 marshal 得到的 JSON 中不会生成该字段。
JSON 命名惯例:total_count

解析字段标签的选项部分(不包括标签的第一部分)的实现:

// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string

// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
	if idx := strings.Index(tag, ","); idx != -1 {
		return tag[:idx], tagOptions(tag[idx+1:])
	}
	return tag, tagOptions("")
}
// https://github.com/golang/go/blob/50bd1c4d4eb4fac8ddeb5f063c099daccfb71b26/src/encoding/json/tags.go
// https://golang.org/pkg/strings/#Index

marshaling 的反向操作将 JSON 解码成 Go 数据结构,称为 unmarshaling,通过 json.Unmarshal 实现。 我们可以构造好数据结构后,然后利用 Unmarshal 筛选 JSON 中的字段。

unmarshaling 操作中将 JSON 字段名关联到 Go 字段的匹配过程是不区分大小写的。