Go 語言之json
Go語言對json的解析函式在encoding/json包裡面,主要是編碼和解碼兩個函式。
Marshal函式
Copyfunc Marshal(v interface{}) ([]byte, error)
Marshal函式返回v的json編碼
注意:
布林型別編碼為json布林型別。
浮點數、整數和Number型別的值編碼為json數字型別。
字串編碼為json字串。
陣列和切片型別的值編碼為json陣列,但[]byte編碼為base64編碼字串,nil切片編碼為null
結構體的值編碼為json物件。每一個匯出欄位變成該物件的一個成員,除非以下兩種情況:
Copy欄位的標籤是"-"
欄位是空值,而其標籤指定了omitempty選項
空值是false、0、""、nil指標、nil介面、長度為0的陣列、切片、對映。物件預設鍵字串是結構體的欄位名,但可以在結構體欄位的標籤裡指定。結構體標籤值裡的"json"鍵為鍵名,後跟可選的逗號和選項,舉例如下:
CopyAge int `json:"-"` // 欄位被本包忽略
Name string `json:"myName"` // 欄位在json裡的鍵為"myName"
Sex int `json:"myName,omitempty"` // 欄位在json裡的鍵為"myName"且如果欄位為空值將在物件中省略掉
Hobby int `json:",omitempty"`// 欄位在json裡的鍵為"Hobby"(預設值),但如果欄位為空值會跳過;注意前導的逗號
"string"選項標記一個欄位在編碼json時應編碼為字串。它只適用於字串、浮點數、整數型別的欄位
CopyInt64String int64 `json:",string"`
如果鍵名是隻含有unicode字元、數字、美元符號、百分號、連字元、下劃線和斜槓的非空字串,將使用它代替欄位名。
匿名的結構體欄位一般序列化為他們內部的匯出欄位就好像位於外層結構體中一樣。如果一個匿名結構體欄位的標籤給其提供了鍵名,則會使用鍵名代替欄位名,而不視為匿名。
Go結構體欄位的可視性規則用於供json決定那個欄位應該序列化或反序列化時是經過修正了的。如果同一層次有多個(匿名)欄位且該層次是最小巢狀的(巢狀層次則使用預設go規則),會應用如下額外規則:
1)json標籤為"-"的匿名欄位強行忽略,不作考慮;
2)json標籤提供了鍵名的匿名欄位,視為非匿名欄位;
3)其餘欄位中如果只有一個匿名欄位,則使用該欄位;
4)其餘欄位中如果有多個匿名欄位,但壓平後不會出現衝突,所有匿名欄位壓平;
5)其餘欄位中如果有多個匿名欄位,但壓平後出現衝突,全部忽略,不產生錯誤。
對匿名結構體欄位的管理是從go1.1開始的,在之前的版本,匿名欄位會直接忽略掉。
Map型別的值編碼為json物件。Map的鍵必須是字串,物件的鍵直接使用對映的鍵。
指標型別的值編碼為其指向的值(的json編碼)。nil指標編碼為null。
介面型別的值編碼為介面內保持的具體型別的值(的json編碼)。nil介面編碼為null。
通道、複數、函式型別的值不能編碼進json。會導致Marshal函式返回UnsupportedTypeError錯誤
Unmarshal函式
Copyfunc Unmarshal(data []byte, v interface{}) error
Unmarshal函式解析json編碼的資料並將結果存入v指向的值。
Unmarshal和Marshal做相反的操作,必要時申請map、切片或指標,遵循如下規則:
要將json資料解碼寫入一個指標,Unmarshal函式首先處理json資料是json字面值null的情況。此時,函式將指標設為nil;否則,函式將json資料解碼寫入指標指向的值;如果指標本身是nil,函式會先申請一個值並使指標指向它。
要將json資料解碼寫入一個結構體,函式會匹配輸入物件的鍵和Marshal使用的鍵(結構體欄位名或者它的標籤指定的鍵名),優先選擇精確的匹配,但也接受大小寫不敏感的匹配。
要將json資料解碼寫入一個介面型別值,函式會將資料解碼為如下型別寫入介面:
CopyBool 對應JSON布林型別
float64 對應JSON數字型別
string 對應JSON字串型別
[]interface{} 對應JSON陣列
map[string]interface{} 對應JSON物件
nil 對應JSON的null
如果一個JSON值不匹配給出的目標型別,或者如果一個json數字寫入目標型別時溢位,Unmarshal函式會跳過該欄位並儘量完成其餘的解碼操作。如果沒有出現更加嚴重的錯誤,本函式會返回一個描述第一個此類錯誤的詳細資訊的UnmarshalTypeError。
JSON的null值解碼為go的介面、指標、切片時會將它們設為nil,因為null在json裡一般表示“不存在”。解碼json的null值到其他go型別時,不會造成任何改變,也不會產生錯誤。
當解碼字串時,不合法的utf-8或utf-16代理(字元)對不視為錯誤,而是將非法字元替換為unicode字元U+FFFD。
示例
Golang - 序列化結構體
Copypackage main
import (
"encoding/json"
"fmt"
)
//定義一個簡單的結構體 Person
type Person struct {
Name string
Age int
Birthday string
Sex float32
Hobby string
}
//寫一個 testStruct()結構體的序列化方法
func testStruct() {
person := Person{
Name: "小崽子",
Age: 50,
Birthday: "2019-09-27",
Sex: 1000.01,
Hobby: "泡妞",
}
// 將Monster結構體序列化
data, err := json.Marshal(&person)
if err != nil {
fmt.Printf("序列化錯誤 err is %v", err)
}
//輸出序列化結果
fmt.Printf("person序列化後 = %v", string(data))
//反序列化
person2 := Person{}
json.Unmarshal(data,&person2)
fmt.Println(person2)
}
func main() {
testStruct()
}
Golang - 序列化map
Copy
package main
import (
"encoding/json"
"fmt"
)
func testMap() {
//定義一個map
var a map[string]interface{}
//使用map之前 必須make一下
a = make(map[string]interface{})
a["name"] = "小崽子"
a["age"] = 8
a["address"] = "上海市浦東新區"
// 將a map結構體序列化
data, err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化錯誤 err is %v", err)
}
//輸出序列化結果
fmt.Printf("map序列化後 = %v", string(data))
//反序列化
var a1 map[string]interface{}
json.Unmarshal(data,&a1)
fmt.Println(a1)
}
func main() {
testMap()
}
Golang - 序列化slice
Copypackage main
import (
"encoding/json"
"fmt"
)
// slice進行序列化
func testSlice() {
var slice []map[string]interface{} // 定義了一個切片,裡面是map格式 map[string]interface{}
var m1 map[string]interface{} //定義切片中的第一個map M1
m1 = make(map[string]interface{})
m1["name"] = "小崽子"
m1["age"] = 16
m1["address"] = [2]string{"上海市", "浦東新區"}
slice = append(slice, m1)
var m2 map[string]interface{} //定義切片中的第2個map M2
m2 = make(map[string]interface{})
m2["name"] = "大崽子"
m2["age"] = 36
m2["address"] = "北京市"
slice = append(slice, m2)
// 將slice進行序列化
data, err := json.Marshal(slice)
if err != nil {
fmt.Printf("序列化錯誤 err is %v", err)
}
//輸出序列化結果
fmt.Printf("slice序列化後 = %v", string(data))
//反序列化結果
var slice2 []map[string]interface{}
json.Unmarshal(data,&slice2)
fmt.Println(slice2)
}
func main() {
testSlice()
}