Go语言中关于JSON的整理

2017-01-22 阅读: Go

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函数,避免了在编码和解码时对反射的调用。

参考

标题:Go语言中关于JSON的整理
本文链接:https://blog.frognew.com/2017/01/json-and-go.html
转载请注明出处。

目录