Go --- Marshal與Unmarshal基礎用法


go語言本身為我們提供了json的工具包”encoding/json”。

前言:

Json–Javascript Object Nanotation 是一種數據交換格式,經常用於前后端的數據傳輸。一端將數據轉換成json字符串,另一端再將json字符串轉換成相應的數據結構,如struct, float等。

用法:

1.Marshal—將數據編碼成json字符串

package main

import (
	"encoding/json"
	"fmt"
)

type Student struct{
	Name string `json:"name"`
	Age int
	sex string
	Class *Class `json:"class"`
}

type Class struct {
	Name string
	Grade int
}

func main() {
	//實例化一個數據結構,用於生成json字符串
	stu := Student{
		Name: "Raily",
		Age: 18,
		sex: "女",
	}
	//指針變量
	cla :=  new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla

	jsonStu, err := json.Marshal(stu)
	if err!= nil{
		return
	}
	//jsonStu是[]byte類型,轉化成string類型便於查看
	fmt.Println(string(jsonStu))
}

輸出結果:

{"name":"Raily","Age":18,"class":{"Name":"1班","Grade":3}}
  • 1

從結果中可以看出:

①只要是可導出成員(變量首字母大寫),都可以轉成json。因成員變量sex是不可導出的,故無法轉成json。

②如果變量打上了json標簽,如Name旁邊的 json:"name" ,那么轉化成的json key就用該標簽“name”,否則取變量名作為key,如“Age”,“HIgh”。

③bool類型也是可以直接轉換為json的value值。Channel, complex 以及函數不能被編碼json字符串。當然,循環的數據結構也不行,它會導致marshal陷入死循環。

④指針變量,編碼時自動轉換為它所指向的值,如cla變量。(當然,不傳指針,Stu struct的成員Class如果換成Class struct類型,效果也是一模一樣的。只不過指針更快,且能節省內存空間。)
最后,強調一句:json編碼成字符串后就是純粹的字符串了。
············································································································

上面的成員變量都是已知的類型,只能接收指定的類型,比如string類型的Name只能賦值string類型的數據。
但有時為了通用性,或使代碼簡潔,我們希望有一種類型可以接受各種類型的數據,並進行json編碼。這就用到了interface{}類型。
如下:

type Student struct {
    Name  interface{} `json:"name"`
    Age   interface{}
    sex   interface{}
    Class interface{} `json:"class"`
}
//其他部分與上面的例子一樣;無論是string,int,bool,還是指針類型等,都可賦值給interface{}類型。

············································································································
在實際項目中,編碼成json串的數據結構,往往是切片類型。如下定義了一個[]StuRead類型的切片:

//方式1:只聲明,不分配內存
var stus1 []*StuRead

//方式2:分配初始值為0的內存
stus2 := make([]*StuRead, 0)

//錯誤示范
//new()只能實例化一個struct
stus := new([]StuRead)

stu1 := StuRead{成員賦值...}
stu2 := StuRead{成員賦值...}

//由方式1和2創建的切片,都能成功追加數據
//方式2最好分配0長度,append時會自動增長。反之指定初始長度,長度不夠時不會自動增長,導致數據丟失
stus1 := appen(stus1,stu1,stu2)
stus2 := appen(stus2,stu1,stu2)

//成功編碼
json1,_ := json.Marshal(stus1)
json2,_ := json.Marshal(stus2)

 

解碼時定義對應的切片接受即可。

2.Unmarshal—將json字符串解碼到相應的數據結構
將上面的例子進行解碼:

type StuRead struct {
    Name  interface{} `json:"name"`
    Age   interface{}
    sex   interface{}
    Class interface{} `json:"class"`
    Test  interface{}
}

type Class struct {
    Name  string
    Grade int
}

func main() {
    //json字符中的"引號,需用\進行轉義,否則編譯出錯
    //json字符串沿用上面的結果,但對key進行了大小的修改,並添加了sex數據
    data:="{\"name\":\"張三\",\"Age\":18,\"sex\":\"男\",\"CLASS\":{\"naME\":\"1班\",\"GradE\":3}}"
   
    str:=[]byte(data)
    //1.Unmarshal的第一個參數是json字符串,第二個參數是接受json解析的數據結構。
    //第二個參數必須是指針,否則無法接收解析的數據,如stu仍為空對象StuRead{}
    //2.可以直接stu:=new(StuRead),此時的stu自身就是指針
    stu:=StuRead{}
    err:=json.Unmarshal(str,&stu)
    //解析失敗會報錯,如json字符串格式不對,缺"號,缺}等。
    if err!=nil{
        fmt.Println(err)
    }

    fmt.Println(stu)
}

結果:

{張三 18 true <nil> map[naME:1班 GradE:3] <nil>}

總結:
① json字符串解析時,需要一個“接收體”接受解析后的數據,且Unmarshal時接收體必須傳遞指針。否則解析雖不報錯,但數據無法賦值到接受體中。如這里用的是StuRead{}接收。

② 解析時,接收體可自行定義。json串中的key自動在接收體中尋找匹配的項進行賦值。匹配規則是:
先查找與key一樣的json標簽,找到則賦值給該標簽對應的變量(如Name)。
沒有json標簽的,就從上往下依次查找變量名與key一樣的變量,如Age。或者變量名忽略大小寫后與key一樣的變量。如Class。第一個匹配的就賦值,后面就算有匹配的也忽略。
(前提是該變量必需是可導出的,即首字母大寫)。
不可導出的變量無法被解析(如sex變量,雖然json串中有key為sex的k-v,解析后其值仍為nil,即空值)

③ 當接收體中存在json串中匹配不了的項時,解析會自動忽略該項,該項仍保留原值。如變量Test,保留空值nil。

④ 你一定會發現,變量Class貌似沒有解析為我們期待樣子。因為此時的Class是個interface{}類型的變量,而json串中key為CLASS的value是個復合結構,不是可以直接解析的簡單類型數據(如“張三”,18,true等)。所以解析時,由於沒有指定變量Class的具體類型,json自動將value為復合結構的數據解析為map[string]interface{}類型的項。也就是說,此時的struct Class對象與StuRead中的Class變量沒有半毛錢關系,故與這次的json解析沒有半毛錢關系。


免責聲明!

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



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