前言
本文主要根據(jù)Go
語(yǔ)言Json
包[1]、官方提供的Json and Go
[2]和go-and-json
[3]整理的渣磷。
Marshal
Marshal
提供對(duì)數(shù)據(jù)進(jìn)行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}`)
注意事項(xiàng):
-
Json
對(duì)象只支持key
為string
,序列化Go map
類(lèi)型時(shí)必須是map[string]T
的形式 -
channel
醋界,complex
和function
類(lèi)型無(wú)法進(jìn)行Json
序列化 - 無(wú)法序列化存在循環(huán)引用的數(shù)據(jù),因?yàn)?code>Marshal會(huì)陷入無(wú)限循環(huán)
- 序列化
pointer
時(shí)是它指向的值(空指針序列化后為null
)
Unmarshal
func Unmarshal(data []byte, v interface{}) error
var m Message
err := json.Unmarshal(b, &m)
//result:如果b包含符合結(jié)構(gòu)體m的有效json格式形纺,那么b中存儲(chǔ)的數(shù)據(jù)就會(huì)保存到m中,比如:
m = Message{
Name: "Alice",
Body: "Hello",
Time: 1294706395881547000,
}
Struct Tags
在Golang
中構(gòu)建字段的時(shí)候我們可能會(huì)在結(jié)構(gòu)體字段名后增加包含在倒引號(hào)(backticks)的Tag
挡篓,如:
type MyStruct struct {
SomeField string `json:"some_field"`
}
-
Json parser
會(huì)根據(jù)Tag
信息去解析字段值 -
Golang
中可導(dǎo)出的字段首字母是大寫(xiě)的,這和我們?cè)?code>Json字段名常用小寫(xiě)是相沖突的官研,通過(guò)Tag
可以有效解決這個(gè)問(wèn)題 - 在
Tag
信息中加入omitempty
關(guān)鍵字后,序列化時(shí)自動(dòng)忽視出現(xiàn)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"`
}
//在這個(gè)例子中楼吃,如果some_field為"":
//加上omitempty后妄讯,序列化后的Json為{}
//如果不加上omitempty酷宵,序列化后的Json為{"some_field": ""}
- 跳過(guò)字段:在
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
}
舉個(gè)栗子浇垦,我們現(xiàn)在要將一個(gè)[]byte
值反序列化為AppWithOrg
的結(jié)構(gòu)體:
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
指針
如果結(jié)構(gòu)體中出現(xiàn)pointer
類(lèi)型,當(dāng)pointer
非nil
時(shí)通過(guò)dereferenced
獲取指針對(duì)應(yīng)的值再進(jìn)行序列化
錯(cuò)誤處理
要注意檢查Marshal
和Unmarshal
返回的err
參數(shù)男韧,序列化時(shí)出現(xiàn)的錯(cuò)誤會(huì)比較少見(jiàn),但當(dāng)Golang
不知道如何將你的數(shù)據(jù)類(lèi)型序列化為Json
時(shí)就會(huì)報(bào)錯(cuò)(比如你嘗試序列化包含nil pointer
的數(shù)據(jù)類(lèi)型時(shí))此虑。
如果你不想處理Marshal
出現(xiàn)的錯(cuò)誤時(shí),你可以將Marshal
出現(xiàn)的錯(cuò)誤轉(zhuǎn)化為panic
:
func MustMarshal(data interface{}) []byte {
out, err := json.Marshal(data)
if err != nil {
panic(err)
}
return out
}
反序列化任意Json數(shù)據(jù)
如果你不知道你要解析的Json
數(shù)據(jù)長(zhǎng)啥樣時(shí)朦前,你可以將其反序列化為任意數(shù)據(jù)類(lèi)型interface{}
//將Json數(shù)據(jù)反序列化為任意類(lèi)型
var parsed interface{}
err := json.Unmarshal(data, &parsed)
//根據(jù)parsed數(shù)據(jù)類(lèi)型做不同的邏輯處理
switch parsed.(type) {
case int:
someGreatIntFunction(parsed.(int))
case map:
someMapThing(parsed.(map))
default:
panic("JSON type not understood")
}
//另一種類(lèi)型判定邏輯
intVal, ok := parsed.(int)
if !ok {
panic("JSON value must be an int")
}
一般情況下,你處理的Json
對(duì)應(yīng)的都是一個(gè)object
况既,你可以將其反序列化為map[string]interface{}
var parsed map[string]interface{}
data := []byte(`
{
"id": "k34rAT4",
"age": 24
}
`)
err := json.Unmarshal(data, &parsed)
//直接調(diào)用
parsed["id"]
//但使用之前仍然需要格式轉(zhuǎn)換
idString := parsed["id"].(string)
除了object
類(lèi)型外,如果你清楚需要解析的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/