JSON作为一种在不同平台间的数据交换格式,Go的标准包encoding/json中实现了对json的编码(marshal)和解码(unmarshal)功能。

json.Marshal

json.Marshal函数实现Json的编码:

  • 如果给定的值不等于nil并且实现了json.Marshaler接口,调用json.Marshaler的MarshalJSON方法完成编码
  • 如果没有实现json.Marshaler接口,而是实现了encoding.TextMarshaler,将调用其MarshalText完成编码
  • 否则将按照下面的默认情况进行编码:
    • bool 编码为 JSON boolean
    • 整形,浮点型等数值 编码为 JSON number
    • string 编码为 JSON string
    • array和slice编码为JSON array, []byte作为例外会被编码成base64 string
    • map[string]interface{}编码为JSON object
    • struct编码为JSON object(只适用struct的可导出字段)
    • nil编码为JSON null

json tag定制struct编码

  • json:"-"忽略字段

    1 struct {
    2		Name string `json:"-"`
    3		No   int
    4	}{"Hello", 112}
    5// {"No":112}
    
  • json:"myName"制定字段名称

    1struct {
    2		Name string `json:"myName"`
    3		No   int
    4	}{"Hello", 112}
    5// {"myName":"Hello","No":112}
    
  • json:",omitempty"json:"myName,omitempty"忽略空值字段

     1struct {
     2	Name string `json:"myName,omitempty"`
     3	No   int
     4}{"Hello", 112}
     5// {"myName":"Hello","No":112}
     6
     7struct {
     8	Name string `json:"myName,omitempty"`
     9	No   int
    10}{}
    11// {"No":0}
    

    关于空值的一个例子

     1foo := struct {
     2	F1 bool
     3	F2 int
     4	F3 float64
     5	F4 string
     6	F5 interface{}
     7	F6 *int
     8	F7 [2]int
     9	F8 []int
    10	F9 map[string]interface{}
    11}{}
    12buf, err := json.MarshalIndent(foo, "", "\t")
    13
    14编码结果为:
    15{
    16"F1": false,
    17"F2": 0,
    18"F3": 0,
    19"F4": "",
    20"F5": null,
    21"F6": null,
    22"F7": [
    23	0,
    24	0
    25],
    26"F8": null,
    27"F9": null
    28}
    
     1foo := struct {
     2	F1 bool                   `json:",omitempty"`
     3	F2 int                    `json:",omitempty"`
     4	F3 float64                `json:",omitempty"`
     5	F4 string                 `json:",omitempty"`
     6	F5 interface{}            `json:",omitempty"`
     7	F6 *int                   `json:",omitempty"`
     8	F7 [2]int                 `json:",omitempty"`
     9	F8 []int                  `json:",omitempty"`
    10	F9 map[string]interface{} `json:",omitempty"`
    11}{}
    12buf, err := json.MarshalIndent(foo, "", "\t")
    13
    14编码结果为:
    15{
    16"F7": [
    17	0,
    18	0
    19]
    20}
    

    json.MarshalIndent编码后的json格式上适合阅读

  • json:",string"

    1struct {
    2	Name string
    3	No   int `json:",string"`
    4}{"Hello", 112}
    5// {"Name":"Hello","No":"112"}
    
  • 内嵌匿名结构会自动展开,可使用json:"myName"取消自动展开

    1type Foo struct {
    2	Name string
    3}
    4type Bar struct {
    5	Foo 
    6	No  int
    7}
    8v := Bar{Foo{"Hello"}, 112}
    9// {"Name":"Hello","No":112}
    
    1type Foo struct {
    2	Name string
    3}
    4type Bar struct {
    5	Foo `json:"Foo"`
    6	No  int
    7}
    8v := Bar{Foo{"Hello"}, 112}
    9// {"Foo":{"Name":"Hello"},"No":112}
    

json.Unmarshal

json.Unmarshal函数实现json的解码。 func Unmarshal(data []byte, v interface{}) error v必须为指针。

json.RawMessage

json.RawMessage此类型的定义为type RawMessage []byte,它还实现了json.Marshaler和json.Unmarshaler接口,可以json的延迟编解码。这里引用官方文档中的例子,简单明了。

 1package main
 2
 3import (
 4	"encoding/json"
 5	"fmt"
 6	"log"
 7)
 8
 9func main() {
10	type Color struct {
11		Space string
12		Point json.RawMessage // delay parsing until we know the color space
13	}
14	type RGB struct {
15		R uint8
16		G uint8
17		B uint8
18	}
19	type YCbCr struct {
20		Y  uint8
21		Cb int8
22		Cr int8
23	}
24
25	var j = []byte(`[
26		{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
27		{"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
28	]`)
29	var colors []Color
30	err := json.Unmarshal(j, &colors)
31	if err != nil {
32		log.Fatalln("error:", err)
33	}
34
35	for _, c := range colors {
36		var dst interface{}
37		switch c.Space {
38		case "RGB":
39			dst = new(RGB)
40		case "YCbCr":
41			dst = new(YCbCr)
42		}
43		err := json.Unmarshal(c.Point, dst)
44		if err != nil {
45			log.Fatalln("error:", err)
46		}
47		fmt.Println(c.Space, dst)
48	}
49}

面向输入输出流的编解码器

json.Encoder和json.Decoder是面向输入输出流的编解码器,它们分别使用io.Reader和io.Writer进行创建,方便我们直接从输入流进行解码和直接编码输出到输出流中。

1func NewDecoder(r io.Reader) *Decoder
2func NewEncoder(w io.Writer) *Encoder

第三方编解码库

因为标准库中json的编解码功能使用了Go的反射特性,因此如果对于性能比较敏感的程序,在github上有一些开源的选项,如https://github.com/pquerna/ffjsonhttps://github.com/mailru/easyjson,这些库一般都是基于go generate为struct生成MarshalJSON和UnmarshalJSON函数,避免了在编码和解码时对反射的调用。

参考