golang中的json處理

JSON(Javascript Object Notation)已經成爲了一種很是流行的數據交換格式,golang 天然不會忽視對 json 的支持,golang 自帶的標準庫就能夠方便的處理 json。另外,推薦一種號稱全世界最快的 JSON 解析器 -- jsoniterhtml

簡介

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

Unmarshal

這是一個反序列化的過程,將 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)
        }
    }
}

Marshal

這是序列化的過程,將結構體序列化成一個 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 字符串.

推薦的 json 解析庫

jsoniter(json-iterator)是一款快且靈活的 JSON 解析器,同時提供 Java 和 Go 兩個版本。從 dsljson 和 jsonparser 借鑑了大量代碼。

jsoniter 的 Golang 版本能夠比標準庫(encoding/json)快 6 倍之多,並且這個性能是在不使用代碼生成的前提下得到的。

可使用 go get github.com/json-iterator/go 進行獲取,徹底兼容標準庫的 MarshalUnmarshal方法。
使用時導入 github.com/json-iterator/go 代替標準庫,基本用法以下:

jsoniter.Marshal(&data)
jsoniter.Unmarshal(input, &data)

參考

  1. JSON處理

  2. json iterator

相關文章
相關標籤/搜索