Json Marshal:將數據編碼成json字符串
看一個簡單的例子
type Stu struct {
Name string `json:"name"`
Age int
HIgh bool
sex string
Class *Class `json:"class"`
}
type Class struct {
Name string
Grade int
}
func main() {
//實例化一個數據結構,用於生成json字符串
stu := Stu{
Name: "張三",
Age: 18,
HIgh: true,
sex: "男",
}
//指針變量
cla := new(Class)
cla.Name = "1班"
cla.Grade = 3
stu.Class=cla
//Marshal失敗時err!=nil
jsonStu, err := json.Marshal(stu)
if err != nil {
fmt.Println("生成json字符串錯誤")
}
//jsonStu是[]byte類型,轉化成string類型便於查看
fmt.Println(string(jsonStu))
}
結果:
{"name":"張三","Age":18,"HIgh":true,"class":{"Name":"1班","Grade":3}}
從結果中可以看出:
- 只要是可導出成員(變量首字母大寫),都可以轉成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{}類型。
Json Unmarshal:將json字符串解碼到相應的數據結構
我們將上面的例子進行解碼
type StuRead struct {
Name interface{} `json:"name"`
Age interface{}
HIgh 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,\"high\":true,\"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自動在接收體中尋找匹配的項進行賦值。匹配規則是: (1) 先查找與key一樣的json標籤,找到則賦值給該標籤對應的變量(如Name)。 (2) 沒有json標籤的,就從上往下依次查找變量名與key一樣的變量,如Age。或者變量名忽略大小寫後與key一樣的變量。如HIgh,Class。第一個匹配的就賦值,後面就算有匹配的也忽略。 (前提是該變量必需是可導出的,即首字母大寫)。
- 不可導出的變量無法被解析(如sex變量,雖然json串中有key爲sex的k-v,解析後其值仍爲nil,即空值)
- 當接收體中存在json串中匹配不了的項時,解析會自動忽略該項,該項仍保留原值。如變量Test,保留空值nil。