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