Go語言對json的解析函數在encoding/json包里面,主要是編碼和解碼兩個函數。
Marshal函數
func Marshal(v interface{}) ([]byte, error)
Marshal函數返回v的json編碼
注意:
布爾類型編碼為json布爾類型。
浮點數、整數和Number類型的值編碼為json數字類型。
字符串編碼為json字符串。
數組和切片類型的值編碼為json數組,但[]byte編碼為base64編碼字符串,nil切片編碼為null
結構體的值編碼為json對象。每一個導出字段變成該對象的一個成員,除非以下兩種情況:
字段的標簽是"-"
字段是空值,而其標簽指定了omitempty選項
空值是false、0、""、nil指針、nil接口、長度為0的數組、切片、映射。對象默認鍵字符串是結構體的字段名,但可以在結構體字段的標簽里指定。結構體標簽值里的"json"鍵為鍵名,后跟可選的逗號和選項,舉例如下:
Age int `json:"-"` // 字段被本包忽略
Name string `json:"myName"` // 字段在json里的鍵為"myName"
Sex int `json:"myName,omitempty"` // 字段在json里的鍵為"myName"且如果字段為空值將在對象中省略掉
Hobby int `json:",omitempty"`// 字段在json里的鍵為"Hobby"(默認值),但如果字段為空值會跳過;注意前導的逗號
"string"選項標記一個字段在編碼json時應編碼為字符串。它只適用於字符串、浮點數、整數類型的字段
Int64String 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函數
func Unmarshal(data []byte, v interface{}) error
Unmarshal函數解析json編碼的數據並將結果存入v指向的值。
Unmarshal和Marshal做相反的操作,必要時申請map、切片或指針,遵循如下規則:
要將json數據解碼寫入一個指針,Unmarshal函數首先處理json數據是json字面值null的情況。此時,函數將指針設為nil;否則,函數將json數據解碼寫入指針指向的值;如果指針本身是nil,函數會先申請一個值並使指針指向它。
要將json數據解碼寫入一個結構體,函數會匹配輸入對象的鍵和Marshal使用的鍵(結構體字段名或者它的標簽指定的鍵名),優先選擇精確的匹配,但也接受大小寫不敏感的匹配。
要將json數據解碼寫入一個接口類型值,函數會將數據解碼為如下類型寫入接口:
Bool 對應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 - 序列化結構體
package 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
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
package 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()
}