前言
本文主要根据Go
语言Json
包[1]、官方提供的Json and Go
[2]和go-and-json
[3]整理的。
Marshal
Marshal
提供对数据进行Json
序列化的功能:
func Marshal(v interface{}) ([]byte, error)
type Message struct {
Name string
Body string
Time int64
}
m := Message{"Alice", "Hello", 1294706395881547000}
b, err := json.Marshal(m)
//result
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
注意事项:
-
Json
对象只支持key
为string
,序列化Go map
类型时必须是map[string]T
的形式 -
channel
,complex
和function
类型无法进行Json
序列化 - 无法序列化存在循环引用的数据,因为
Marshal
会陷入无限循环 - 序列化
pointer
时是它指向的值(空指针序列化后为null
)
Unmarshal
func Unmarshal(data []byte, v interface{}) error
var m Message
err := json.Unmarshal(b, &m)
//result:如果b包含符合结构体m的有效json格式,那么b中存储的数据就会保存到m中,比如:
m = Message{
Name: "Alice",
Body: "Hello",
Time: 1294706395881547000,
}
Struct Tags
在Golang
中构建字段的时候我们可能会在结构体字段名后增加包含在倒引号(backticks)的Tag
,如:
type MyStruct struct {
SomeField string `json:"some_field"`
}
-
Json parser
会根据Tag
信息去解析字段值 -
Golang
中可导出的字段首字母是大写的,这和我们在Json
字段名常用小写是相冲突的,通过Tag
可以有效解决这个问题 - 在
Tag
信息中加入omitempty
关键字后,序列化时自动忽视出现zero-value
情形的字段。-
number
的zero-value
为0 -
string
的zero-value
为empty string
-
map
、slice
和pointer
的zero-value
为nil
-
type MyStruct struct {
SomeField string `json:"some_field,omitempty"`
}
//在这个例子中,如果some_field为"":
//加上omitempty后,序列化后的Json为{}
//如果不加上omitempty,序列化后的Json为{"some_field": ""}
- 跳过字段:在
Tag
中加入"-"
type App struct {
Id string `json:"id"`
Password string `json:"-"`
}
嵌套字段
Golang
支持struct
的嵌套,如:
type App struct {
Id string `json:"id"`
}
type Org struct {
Name string `json:"name"`
}
type AppWithOrg struct {
App
Org
}
举个栗子,我们现在要将一个[]byte
值反序列化为AppWithOrg
的结构体:
data := []byte(`
{
"id": "k34rAT4",
"name": "My Awesome Org"
}
`)
var appWithOrg AppWithOrg
err := json.Unmarshal(data, &appWithOrg)
app := appWithOrg.App
org := appWithOrg.Org
// AND/OR
appId := appWithOrg.Id
orgName := appWithOrg.Name
指针
如果结构体中出现pointer
类型,当pointer
非nil
时通过dereferenced
获取指针对应的值再进行序列化
错误处理
要注意检查Marshal
和Unmarshal
返回的err
参数,序列化时出现的错误会比较少见,但当Golang
不知道如何将你的数据类型序列化为Json
时就会报错(比如你尝试序列化包含nil pointer
的数据类型时)。
如果你不想处理Marshal
出现的错误时,你可以将Marshal
出现的错误转化为panic
:
func MustMarshal(data interface{}) []byte {
out, err := json.Marshal(data)
if err != nil {
panic(err)
}
return out
}
反序列化任意Json数据
如果你不知道你要解析的Json
数据长啥样时,你可以将其反序列化为任意数据类型interface{}
//将Json数据反序列化为任意类型
var parsed interface{}
err := json.Unmarshal(data, &parsed)
//根据parsed数据类型做不同的逻辑处理
switch parsed.(type) {
case int:
someGreatIntFunction(parsed.(int))
case map:
someMapThing(parsed.(map))
default:
panic("JSON type not understood")
}
//另一种类型判定逻辑
intVal, ok := parsed.(int)
if !ok {
panic("JSON value must be an int")
}
一般情况下,你处理的Json
对应的都是一个object
,你可以将其反序列化为map[string]interface{}
var parsed map[string]interface{}
data := []byte(`
{
"id": "k34rAT4",
"age": 24
}
`)
err := json.Unmarshal(data, &parsed)
//直接调用
parsed["id"]
//但使用之前仍然需要格式转换
idString := parsed["id"].(string)
除了object
类型外,如果你清楚需要解析的Json
格式,可以做如下反序列化:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
Reference
[1]https://golang.org/pkg/encoding/json/#example_Decoder
[2]https://blog.golang.org/json-and-go
[3]https://eager.io/blog/go-and-json/