Go Json操作

引用包

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 {
ID int
Name string
Colors []string
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
b, err := json.Marshal(group)
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b)

Output:
{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}

结构体必须是大写字母开头的成员才会被 JSON 处理到,小写字母开头的成员不会有影响。

结构体的成员变量名将会直接作为 JSON Object 的 key 打包成 JSON

Decode

将 JSON 数据解码

func Unmarshal(data []byte, v interface{}) error

类型转换规则和上面的规则类似

var jsonBlob = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
type Animal struct {
Name string
Order string
}
var animals []Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", animals)

Output:
[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

会自动匹配对应的变量名进行赋值,大小写不敏感。

如果 JSON 中有多余的字段,会被直接抛弃掉;如果 JSON 缺少某个字段,则直接忽略不对结构体中变量赋值,不会报错。

StructTag

如果希望手动配置结构体的成员和 JSON 字段的对应关系,可以在定义结构体的时候给成员打标签:

使用omitempty熟悉,如果该字段为 nil 或 0 值(数字 0, 字符串 “”, 空数组 [] 等),则打包的 JSON 结果不会有这个字段。

type Message struct {
Name string `json:"msg_name"` // 对应JSON的msg_name
Body string `json:"body,omitempty"` // 如果为空置则忽略字段
Time int64 `json:"-"` // 直接忽略字段
}
var m = Message{
Name: "Alice",
Body: "",
Time: 1294706395881547000,
}
data, err := json.Marshal(m)
if err != nil {
fmt.Printf(err.Error())
return
}
fmt.Println(string(data))

Output:
{"msg_name":"Alice"}

更灵活地使用 JSON

使用 json.RawMessage

json.RawMessage 其实就是 []byte 类型的重定义。可以进行强制类型转换。

现在有这么一种场景,结构体中的其中一个字段的格式是未知的:

type Command struct {
ID int
Cmd string
Args *json.RawMessage
}

使用 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 {
MarshalJSON() ([]byte, error)
}
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}

实现该接口的对象需要将自己的数据打包和解包。如果实现了该接口,json 在打包解包时则会调用自定义的方法,不再对该对象进行其他处理。

0%