青蛙小白
博客 / 2017/01

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:"-"忽略字段

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

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

    struct {
    	Name string `json:"myName,omitempty"`
    	No   int
    }{"Hello", 112}
    // {"myName":"Hello","No":112}
    
    struct {
    	Name string `json:"myName,omitempty"`
    	No   int
    }{}
    // {"No":0}

    关于空值的一个例子

    foo := struct {
    	F1 bool
    	F2 int
    	F3 float64
    	F4 string
    	F5 interface{}
    	F6 *int
    	F7 [2]int
    	F8 []int
    	F9 map[string]interface{}
    }{}
    buf, err := json.MarshalIndent(foo, "", "\t")
    
    编码结果为:
    {
    "F1": false,
    "F2": 0,
    "F3": 0,
    "F4": "",
    "F5": null,
    "F6": null,
    "F7": [
    	0,
    	0
    ],
    "F8": null,
    "F9": null
    }
    foo := struct {
    	F1 bool                   `json:",omitempty"`
    	F2 int                    `json:",omitempty"`
    	F3 float64                `json:",omitempty"`
    	F4 string                 `json:",omitempty"`
    	F5 interface{}            `json:",omitempty"`
    	F6 *int                   `json:",omitempty"`
    	F7 [2]int                 `json:",omitempty"`
    	F8 []int                  `json:",omitempty"`
    	F9 map[string]interface{} `json:",omitempty"`
    }{}
    buf, err := json.MarshalIndent(foo, "", "\t")
    
    编码结果为:
    {
    "F7": [
    	0,
    	0
    ]
    }

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

  • json:",string"

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

    type Foo struct {
    	Name string
    }
    type Bar struct {
    	Foo 
    	No  int
    }
    v := Bar{Foo{"Hello"}, 112}
    // {"Name":"Hello","No":112}
    type Foo struct {
    	Name string
    }
    type Bar struct {
    	Foo `json:"Foo"`
    	No  int
    }
    v := Bar{Foo{"Hello"}, 112}
    // {"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的延迟编解码。这里引用官方文档中的例子,简单明了。

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	type Color struct {
		Space string
		Point json.RawMessage // delay parsing until we know the color space
	}
	type RGB struct {
		R uint8
		G uint8
		B uint8
	}
	type YCbCr struct {
		Y  uint8
		Cb int8
		Cr int8
	}

	var j = []byte(`[
		{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
		{"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
	]`)
	var colors []Color
	err := json.Unmarshal(j, &colors)
	if err != nil {
		log.Fatalln("error:", err)
	}

	for _, c := range colors {
		var dst interface{}
		switch c.Space {
		case "RGB":
			dst = new(RGB)
		case "YCbCr":
			dst = new(YCbCr)
		}
		err := json.Unmarshal(c.Point, dst)
		if err != nil {
			log.Fatalln("error:", err)
		}
		fmt.Println(c.Space, dst)
	}
}

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

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

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

第三方编解码库

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

参考

TAGS # go
评论