Go语言中关于JSON的整理
2017-01-22
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/ffjson和https://github.com/mailru/easyjson,这些库一般都是基于go generate为struct生成MarshalJSON和UnmarshalJSON函数,避免了在编码和解码时对反射的调用。