JSON(Javascript Object Notation)已經成爲了一種很是流行的數據交換格式,golang 天然不會忽視對 json 的支持,golang 自帶的標準庫就能夠方便的處理 json。另外,推薦一種號稱全世界最快的 JSON 解析器 -- jsoniter
。html
json 中提供的處理 json 的標準包是 encoding/json
,主要使用的是如下兩個方法:git
// 序列化 func Marshal(v interface{}) ([]byte, error) // 反序列化 func Unmarshal(data []byte, v interface{}) error
序列化先後的數據結構有如下的對應關係:github
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
這是一個反序列化的過程,將 JSON 串從新組裝成結構體。golang
示例代碼以下:web
package main import ( "encoding/json" "fmt" ) type Animal struct { Name string Order string } func main() { var jsonBlob = []byte(`[ {"Name": "Platypus", "Order": "Monotremata"}, {"Name": "Quoll", "Order": "Dasyuromorphia"} ]`) var animals []Animal err := json.Unmarshal(jsonBlob, &animals) if err != nil { fmt.Println("error:", err) } fmt.Printf("%+v", animals) }
運行後,輸出結果:[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
能夠看出,結構體字段名與 JSON 裏的 KEY 一一對應.
例如 JSON 中的 KEY 是 Name,那麼怎麼找對應的字段呢?json
首先查找 tag 含有 Name 的可導出的 struct 字段(首字母大寫)數組
其次查找字段名是 Name 的導出字段數據結構
最後查找相似 NAME 或者 NAmE 等這樣的除了首字母以外其餘大小寫不敏感的導出字段app
注意:可以被賦值的字段必須是可導出字段!!性能
同時 JSON 解析的時候只會解析能找獲得的字段,找不到的字段會被忽略,這樣的一個好處是:當你接收到一個很大的 JSON 數據結構而你卻只想獲取其中的部分數據的時候,你只需將你想要的數據對應的字段名大寫,便可輕鬆解決這個問題。
前面說的是,已知要解析的類型,好比說,當看到 JSON arrays 時定義一個 golang 數組進行接收數據, 看到 JSON objects 時定義一個 map 來接收數據,那麼這個時候怎麼辦?答案是使用 interface{} 進行接收,而後配合 type assert 進行解析,好比:
var f interface{} b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`) json.Unmarshal(b, &f) for k, v := range f.(map[string]interface{}) { switch vv := v.(type) { case string: fmt.Println(k, "is string", vv) case int: fmt.Println(k, "is int ", vv) case float64: fmt.Println(k, "is float64 ", vv) case []interface{}: fmt.Println(k, "is array:") for i, j := range vv { fmt.Println(i, j) } } }
這是序列化的過程,將結構體序列化成一個 JSON 串。
示例代碼以下:
package main import ( "encoding/json" "fmt" ) type Animal struct { Name string `json:"name"` Order string `json:"order"` } func main() { var animals []Animal animals = append(animals, Animal{Name: "Platypus", Order: "Monotremata"}) animals = append(animals, Animal{Name: "Quoll", Order: "Dasyuromorphia"}) jsonStr, err := json.Marshal(animals) if err != nil { fmt.Println("error:", err) } fmt.Println(string(jsonStr)) }
運行後,輸出結果:
[{"name":"Platypus","order":"Monotremata"},{"name":"Quoll","order":"Dasyuromorphia"}]
能夠發現,序列化獲得的 json 串的 key 名字跟結構體 json tag 後指定的名字同樣.
當結構體字段後無 json tag 時,獲得的 json 串的 key 名與字段名一致。
json tag 有不少值能夠取,同時有着不一樣的含義,好比:
tag 是 "-",表示該字段不會輸出到 JSON.
tag 中帶有自定義名稱,那麼這個自定義名稱會出如今 JSON 的字段名中,好比上面小寫字母開頭的 name
.
tag 中帶有 "omitempty" 選項,那麼若是該字段值爲空,就不會輸出到JSON 串中.
若是字段類型是 bool, string, int, int64 等,而 tag 中帶有",string" 選項,那麼該字段在輸出到 JSON 時,會把該字段對應的值轉換成 JSON 字符串.
jsoniter(json-iterator)是一款快且靈活的 JSON 解析器,同時提供 Java 和 Go 兩個版本。從 dsljson 和 jsonparser 借鑑了大量代碼。
jsoniter 的 Golang 版本能夠比標準庫(encoding/json)快 6 倍之多,並且這個性能是在不使用代碼生成的前提下得到的。
可使用 go get github.com/json-iterator/go
進行獲取,徹底兼容標準庫的 Marshal
和 Unmarshal
方法。
使用時導入 github.com/json-iterator/go
代替標準庫,基本用法以下:
jsoniter.Marshal(&data) jsoniter.Unmarshal(input, &data)