JSON(JavaScript 對象表示,JavaScript Object Notation)作為一種輕量級的數據交換格式,常用於前后端數據傳輸。
Go 語言通過 encoding/json 對外提供標准的 JSON 序列化和反序列化方法,即 encoding/json.Marshal 和 encoding/json.Unmarshal。
json.Marshal
將數據編碼成json字符串。
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"user_name"`
Age int `json:"age"`
sex string
Work1 *Work1
Work2 *Work2
Work3 Work3
Work4 interface{} `json:"work4"`
}
type Work1 struct {
Name string `json:"work1_name"`
Salary float32
}
type Work2 struct {
Name string `json:"work2_name"`
Salary float32
}
type Work3 struct {
Name string `json:"work3_name"`
Salary float32
}
type Work4 struct {
Name string `json:"work4_name"`
Salary float32
Address string `json:"work4_add"`
}
func main() {
// 實例化User
u1 := User{
Name: "ares",
Age: 18,
sex: "男",
}
// 指針
w1 := Work1{
Name: "god1",
Salary: 100,
}
u1.Work1 = &w1
// 指針
w2 := new(Work2)
w2.Name = "god2"
w2.Salary = 200
u1.Work2 = w2
// 非指針
w3 := Work3{
Name: "god3",
Salary: 300,
}
u1.Work3 = w3
// 非指針
w4 := Work4{
Name: "god4",
Salary: 400,
Address: "cbd",
}
u1.Work4 = w4
//Marshal失敗時err!=nil
jsonU, err := json.Marshal(u1)
if err != nil {
fmt.Println("生成json字符串錯誤")
}
// jsonU是[]byte類型,轉化成string類型便於查看
// {"user_name":"ares","age":18,"Work1":{"work1_name":"god1","Salary":100},"Work2":{"work2_name":"god2","Salary":200},"Work3":{"work3_name":"god3","Salary":300},"work4":{"work4_name":"god4","Salary":400,"work4_add":"cbd"}}
fmt.Println(string(jsonU))
}
只要是可導出成員(變量首字母大寫),都可以轉成json。sex是小寫,故不可以轉成json。
若存在json標簽,那么轉化成的json key就用該標簽,否則取變量名作為key。
指針變量,編碼時自動轉換為它所指向的值。
bool類型也是可以直接轉換為json的value值。Channel, complex 以及函數不能被編碼json字符串。
interface{}類型是個空接口,任何其他類型的數據都可以賦值給interface{}類型。
Json Unmarshal
將json字符串解碼到相應的數據結構。
import (
"encoding/json"
"fmt"
"reflect"
)
type User struct {
Name string `json:"user_name"`
Age int `json:"age"`
sex string
Work1 *Work1
Work2 json.RawMessage
Work3 Work3
Work4 interface{} `json:"work4"`
Work5 interface{}
}
type Work1 struct {
Name string `json:"work1_name"`
Salary float32
}
type Work2 struct {
Name string `json:"work2_name"`
Salary float32
}
type Work3 struct {
Name string `json:"work3_name"`
Salary float32
}
type Work4 struct {
Name string `json:"work4_name"`
Salary float32
Address string `json:"work4_add"`
}
func main() {
//json字符中的"引號,需用\進行轉義,否則編譯出錯
data := "{\"user_name\":\"ares\",\"sex\":\"男\",\"age\":18,\"Work1\":{\"work1_name\":\"god1\",\"Salary\":100},\"Work2\":{\"work2_name\":\"god2\",\"Salary\":200},\"Work3\":{\"work3_name\":\"god3\",\"Salary\":300},\"work4\":{\"work4_name\":\"god4\",\"Salary\":400,\"work4_add\":\"cbd\"}}"
str := []byte(data)
u1 := User{}
// Unmarshal的第一個參數是json字符串,第二個參數是接受json解析的數據結構.第二個參數必須是指針,否則無法接收解析的數據,
err := json.Unmarshal(str, &u1)
if err != nil {
fmt.Println("Unmarshal err,", err)
}
// {ares 18 0xc0000a41c8 0xc0000a41e0 {god3 300} map[Salary:400 work4_add:cbd work4_name:god4]} Work2 為*Work2類型
// Work2 為json.RawMessage類型 {ares 18 0xc0000a4198 [123 34 119 111 114 107 50 95 110 97 109 101 34 58 34 103 111 100 50 34 44 34 83 97 108 97 114 121 34 58 50 48 48 125] {god3 300} map[Salary:400 work4_add:cbd work4_name:god4] <nil>}
fmt.Println(u1)
// 查看類型
nameType := reflect.TypeOf(u1.Name)
ageType := reflect.TypeOf(u1.Age)
sexType := reflect.TypeOf(u1.sex)
work1Type := reflect.TypeOf(u1.Work1)
work2Type := reflect.TypeOf(u1.Work2)
work3Type := reflect.TypeOf(u1.Work3)
work4Type := reflect.TypeOf(u1.Work4)
work5Type := reflect.TypeOf(u1.Work5)
fmt.Println(nameType) // string
fmt.Println(ageType) // int
fmt.Println(sexType) // string
fmt.Println(work1Type) // *main.Work1
fmt.Println(work2Type) // json.RawMessage
fmt.Println(work3Type) // main.Work3
fmt.Println(work4Type) // map[string]interface {}
fmt.Println(work5Type) // <nil>
}
json字符串解析時,需要一個“接收體”接受解析后的數據,且Unmarshal時接收體必須傳遞指針。
解析時,接收體可自行定義。json串中的key自動在接收體中尋找匹配的項進行賦值。
匹配規則:先查找與key一樣的json標簽,找到則賦值給該標簽對應的變量;沒有json標簽的,就從上往下依次查找變量名與key一樣的變量,或者變量名忽略大小寫后與key一樣的變量,第一個匹配的就賦值,后面就算有匹配的也忽略(變量可導出,首字母大寫)。
當接收體中存在json串中匹配不了的項時,解析會自動忽略該項,該項仍保留原值。如變量Work5,保留空值nil。
json解析后,json串中value,只要是"簡單數據",都會按照默認的類型賦值。
簡單數據:是指不能再進行二次json解析的數據,例如name
復合數據:是可進行二次甚至多次json解析的,因為它的value也是個可被解析的獨立json,例如work1-5。
對於"復合數據",如果接收體中配的項被聲明為interface{}類型,go都會默認解析成map[string]interface{}類型。如果想直接解析到struct Class對象中,可以將接受體對應的項定義為該struct類型。
如果不想指定work變量為具體的類型,仍想保留interface{}類型,但又希望該變量可以解析到struct work對象中,可以將該變量定義為json.RawMessage類型。
被聲明為json.RawMessage類型的變量在json解析時,變量值仍保留json的原值,即未被自動解析為map[string]interface{}類型,,可以對該變量進行二次json解析,因為其值仍是個獨立且可解析的完整json串,只需再定義一個新的接受體即可。