Go的json解析:Marshal與Unmarshal


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串,只需再定義一個新的接受體即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM