引用包
import "encoding/json" |
Encode
将一个对象编码成 JSON 数据,接受一个 interface{} 对象,返回 []byte 和 error:
func Marshal(v interface{}) ([]byte, error)
Marshal 函数将会递归遍历整个对象,依次按成员类型对这个对象进行编码,类型转换规则如下:
- bool 类型 转换为 JSON 的 Boolean
- 整数,浮点数等数值类型 转换为 JSON 的 Number
- string 转换为 JSON 的字符串 ( 带 “” 引号 )
- struct 转换为 JSON 的 Object,再根据各个成员的类型递归打包
- 数组或切片 转换为 JSON 的 Array
- []byte 会先进行 base64 编码然后转换为 JSON 字符串
- map 转换为 JSON 的 Object,key 必须是 string
- interface{} 按照内部的实际类型进行转换
- nil 转为 JSON 的 null
- channel,func 等类型 会返回 UnsupportedTypeError
type ColorGroup struct { |
结构体必须是大写字母开头的成员才会被 JSON 处理到,小写字母开头的成员不会有影响。
结构体的成员变量名将会直接作为 JSON Object 的 key 打包成 JSON
Decode
将 JSON 数据解码
func Unmarshal(data []byte, v interface{}) error
类型转换规则和上面的规则类似
var jsonBlob = []byte(`[ |
会自动匹配对应的变量名进行赋值,大小写不敏感。
如果 JSON 中有多余的字段,会被直接抛弃掉;如果 JSON 缺少某个字段,则直接忽略不对结构体中变量赋值,不会报错。
StructTag
如果希望手动配置结构体的成员和 JSON 字段的对应关系,可以在定义结构体的时候给成员打标签:
使用omitempty
熟悉,如果该字段为 nil 或 0 值(数字 0, 字符串 “”, 空数组 [] 等),则打包的 JSON 结果不会有这个字段。
type Message struct { |
更灵活地使用 JSON
使用 json.RawMessage
json.RawMessage 其实就是 []byte 类型的重定义。可以进行强制类型转换。
现在有这么一种场景,结构体中的其中一个字段的格式是未知的:
type Command struct { |
使用 json.RawMessage 的话,Args 字段在 Unmarshal 时不会被解析,直接将字节数据赋值给 Args。我们可以能先解包第一层的 JSON 数据,然后根据 Cmd 的值,再确定 Args 的具体类型进行第二次 Unmarshal。
这里要注意的是,一定要使用指针类型 *json.RawMessage,否则在 Args 会被认为是 []byte 类型,在打包时会被打包成 base64 编码的字符串。
使用 interface{}
interface{} 类型在 Unmarshal 时,会自动将 JSON 转换为对应的数据类型:
- JSON 的 boolean 转换为 bool
- JSON 的数值 转换为 float64
- JSON 的字符串 转换为 string
- JSON 的 Array 转换为 []interface{}
- JSON 的 Object 转换为 map[string]interface{}
- JSON 的 null 转换为 nil
需要注意的有两个。一个是所有的 JSON 数值自动转换为 float64 类型,使用时需要再手动转换为需要的 int,int64 等类型。第二个是 JSON 的 object 自动转换为 map[string]interface{} 类型,访问时直接用 JSON Object 的字段名作为 key 进行访问。再不知道 JSON 数据的格式时,可以使用 interface{}。
自定义类型
如果希望自己定义对象的打包解包方式,可以实现以下的接口:
type Marshaler interface { |
实现该接口的对象需要将自己的数据打包和解包。如果实现了该接口,json 在打包解包时则会调用自定义的方法,不再对该对象进行其他处理。