Golang实现Json序列化

Golang实现Json序列化

学习自:https://golang.org/pkg/encoding/json/#Marshal

先来看看api的使用:

1
func Marshal(v interface{}) ([]byte, error)

基本作用就是返回v的json编码

作用过程

Marshal递归地遍历v,如果遇到实现了Marshaler接口的值并且不是nil指针,Marshal会调用MarshalJSON方法来生成JSON。如果不存在MarshalJSON方法,但该值实现了encoding.TextMarshaler,则Marshal会调用MarshalText方法将结果编码为JSON字符。

编码结果

Marshal使用以下类型相关的默认编码:

  • bool值编码为JSON的布尔值;
  • 浮点数、整数和number值编码为JSON数字
  • 字符串值编码为有效的UTF-8的JSON字符串,并且会用Unicode替换无效字节

为了防止某些浏览器会将JSON输出解析为HTML,尖括号<和>被转义为03c03e。基于相同的原因,符号&会被转义为026

可以使用调用了SetEscapeHTML(false)的编码器禁止此转义

  • 数组和切片值编码为JSON数组,但了[]字节会被编码为base64编码的字符串,而nil切片编码为空JSON值
  • 结构体则是编码为JSON对象,每个structure字段都会成为JSON对象的成员,并且会使用该字段名称作为对象值

关于structure编码为JSON

在golang的结构体中,每个成员变量都可以附带一个Tag说明,因此每个struct字段的编码可以通过存储在以Json为key的tag进行定制化。比如:

1
2
3
4
type User struct {
UserId int `json:"user_id,omitempty" bson:"user_id"`
UserName string `json:"user_name" bson:"user_name"`
}

这些格式化字符串给出了字符的名称,还可以通过逗号在后面加上一系列的选项。tag中如果带有”omitempty”选项,那么如果该字段值为空,就不会输出到JSON串中。

还有一种特别的情况,如果字段标记为“ - ”,则始终省略该字段。请注意,比较特别的是仍然可以使用标记“ - ,”生成名称为“ - ”的字段。比如:

1
2
3
4
5
// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "-".
Field int `json:"-,"`

“string”选项表示字段在JSON编码的字符串中存储为JSON。它仅适用于字符串,浮点,整数或布尔类型的字段。在与JavaScript程序通信时,有时会使用这种额外的编码级别。

其它

map

map被编码为JSON对象,而且map的key类型必须是字符串、整数或者实现了encoding.TextMarshaler。其中:

  • 字符串类型会被直接实现
  • encoding.TextMarshaler的会被marshaled
  • 整数则会转为字符串

接口

接口会被编码为接口中包含的值,nil接口值则被编码为null JSON值

另外:

Channel, complex, and function values cannot be encoded in JSON. Attempting to encode such a value causes Marshal to return an UnsupportedTypeError.

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

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

func main() {
type ColorGroup struct {
ID int
Name string
Colors []string
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
b, err := json.Marshal(group)
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b)
}