Go如何實現(xiàn)json字符串與各類struct相互轉(zhuǎn)換
json字符串與各類struct相互轉(zhuǎn)換
不廢話了都在代碼中了
package main import ( "fmt" "reflect" "encoding/json" "strings" ) type Class struct { Grade int `json:"grade"` //年級 ClassNumber int `json:"classNumber"` //班級號 } type Student struct{ Name string //大寫開頭,可被導出,沒有`json:".."`,導出json的字段名是原本名稱 age int //小寫開題,不可被導出 Hight int `json:"currentHight"` //導出對應(yīng)json的字段名為currentHight Class *Class `class` //指針,指向引用對象;如果不用指針,只是值復制 } func doMarshal(){//對象轉(zhuǎn)json字符串 nClass:=new(Class)//new只給給特定類型分配內(nèi)存,設(shè)置“零”值,返回其地址(指針) fmt.Printf("nClass的類型是%s,內(nèi)容是%v\n",reflect.TypeOf(nClass),*nClass) nClass.Grade=3 nClass.ClassNumber=6 nStudents:=make([]*Student,0) //make只用于map,slice和channel,并且不顯示返回指針 //這個切片,存放Student的指針 nStudent:=Student{"Lily",7,116,nClass} jsonBytes,err1:=json.Marshal(nStudent)//解析后的是[]byte if err1!=nil{ fmt.Printf("轉(zhuǎn)json失敗:%v\n",err1) return } fmt.Println("轉(zhuǎn)成的JSON:") //age不會被導出 //{"Name":"Lily","currentHight":116,"Class":{"grade":3,"classNumber":6}} fmt.Println(string(jsonBytes)) nStudents=append(nStudents,&Student{"Lilei",8,130,nClass}) nStudents=append(nStudents,&nStudent) josnListBytes,err2:=json.Marshal(nStudents) if err2!=nil{ fmt.Printf("轉(zhuǎn)jsonList失?。?v\n",err2) return } fmt.Println("轉(zhuǎn)成的列表型JSON:") fmt.Println(string(josnListBytes)) //[{"Name":"Lilei","currentHight":130,"Class":{"grade":3,"classNumber":6}},{"Name":"Lily","currentHight":116,"Class":{"grade":3,"classNumber":6}}] } func doUnMarshal(){//json字符串轉(zhuǎn)對象 jsonStr:=` { "Name":"Lily", "currentHight":116, "age":12, "Class":{ "grade":3, "classNumber":6 }, "score":[98,100,95] } ` jsonListStr:=`[ { "Name":"Lucy", "currentHight":120, "Class":{ "grade":3, "classNumber":5 } }, { "Name":"Lily", "currentHight":116, "Class":{ "grade":3, "classNumber":6 } } ]` //第一種解析json方式,解析到Struct/[]Struct student:=Student{}//同new(Student) err:=json.Unmarshal([]byte(jsonStr),&student) //Unmarshall第2個參數(shù)必須是指針,否則報錯:json: Unmarshal(non-pointer main.Student) //因為必須解析到具體的對象,所以需傳入對象引用,而不是值傳遞 //score在Student中沒有此字段,所以被忽略了 if err!=nil{ fmt.Printf("解析json字符串異常:%s\n",err) } fmt.Printf("學生的名稱是%v,班級信息是%v,年齡是%v(私有對象不能導入,初始為0)\n",student.Name,*student.Class,student.age) //學生的名稱是Lily,學生的班級信息是{3 6},學生的年齡是0 students:=[]*Student{} //定義切片,同make([]*Student,0) err=json.Unmarshal([]byte(jsonListStr),&students) if err!=nil{ fmt.Printf("解析json字符串異常:%s\n",err) } for _,stu:=range students{ //這里stu是指針類型,獲取其屬性可以直接用.Name,也可以解引用后用.Name fmt.Printf("列表:學生的名稱是%s,身高是%d,在%d年級%d班\n",stu.Name,(*stu).Hight,(*stu.Class).Grade,stu.Class.ClassNumber) } //第二種解析到interface{}/[]interface{} fmt.Println("*************解析json*************") var student1 interface{} err=json.Unmarshal([]byte(jsonStr),&student1) if err!=nil{ fmt.Printf("解析json字符串異常:%s\n",err) } c:=-1 resolve2JosnObj(student1,c) /* *************解析json************* map元素: map[Name]的元素: 類型是string,值是 Lily map[currentHight]的元素: 類型float64,值是 116 map[age]的元素: 類型float64,值是 12 map[Class]的元素: map元素: ---map[classNumber]的元素: 類型float64,值是 6 ---map[grade]的元素: 類型float64,值是 3 map[score]的元素: list元素: ---第0個元素: 類型float64,值是 98 ---第1個元素: 類型float64,值是 100 ---第2個元素: 類型float64,值是 95 */ fmt.Println("*************解析jsonlist*************") var students1 interface{} err=json.Unmarshal([]byte(jsonListStr),&students1) if err!=nil{ fmt.Printf("解析jsonlist字符串異常:%s\n",err) } d:=-1 resolve2JosnObj(students1,d) /* *************解析jsonlist************* list元素: 第0個元素: map元素: ---map[Name]的元素: 類型是string,值是 Lucy ---map[currentHight]的元素: 類型float64,值是 120 ---map[Class]的元素: map元素: ------map[grade]的元素: 類型float64,值是 3 ------map[classNumber]的元素: 類型float64,值是 5 第1個元素: map元素: ---map[Class]的元素: map元素: ------map[grade]的元素: 類型float64,值是 3 ------map[classNumber]的元素: 類型float64,值是 6 ---map[Name]的元素: 類型是string,值是 Lily ---map[currentHight]的元素: 類型float64,值是 116 */ } func resolve2JosnObj(objI interface{},c int){ c=c+1 switch obj:=objI.(type) { //此處[interface{}].(type) 專門用于switch的類型判斷 case string: fmt.Println("類型是string,值是",obj) case float64: fmt.Println("類型float64,值是",obj) case map[string]interface{}: fmt.Println("map元素:") for k,vi:=range obj{ fmt.Printf("%smap[%s]的元素: ",strings.Repeat("---",c),k) resolve2JosnObj(vi,c) } case []interface{}: fmt.Println("list元素:") for i,vi:=range obj{ fmt.Printf("%s第%d個元素: ",strings.Repeat("---",c),i) resolve2JosnObj(vi,c) } default: fmt.Println("無法判斷類型,類型是",reflect.TypeOf(obj),"值是",obj) } } func main() { doMarshal()//對象轉(zhuǎn)json字符串 doUnMarshal() }
簡單總結(jié)
1、結(jié)構(gòu)體對象可生成json字符串,Marshal()是[]byte,需要string去轉(zhuǎn)換
2、json字符串可以映射到一個struct,但僅限公共元素(大寫開頭);也可通用的轉(zhuǎn)換到空接口interfece[],使用對應(yīng)轉(zhuǎn)換到需要的內(nèi)容
結(jié)構(gòu)體轉(zhuǎn)換為JSON字符串的一個坑
通過json.Marshal來將結(jié)構(gòu)體數(shù)據(jù)轉(zhuǎn)換為json字符串時,需要注意結(jié)構(gòu)體內(nèi)成員變量的首字母大小寫的問題,很容易會掉進坑里.
來看一下這個例子
package main import ( "encoding/json" "fmt" ) type Student struct { Name string age int } func main() { var s Student = Student { Name: "xiaomo", age: 18, } fmt.Printf("%+v\n", s) res, _ := json.Marshal(s) fmt.Println(string(res)) }
運行輸出如下:
$ go run test_json.go
{Name:xiaomo age:18}
{"Name":"xiaomo"}
可以看到轉(zhuǎn)換的json字符串中只包含了Name字段,age字段被忽略了.這是由于在進行json解析時,只會轉(zhuǎn)換結(jié)構(gòu)體能夠?qū)С龅淖侄?首字母大寫),其他字段將會被忽略.
這個機制也有個好處,可以根據(jù)實際需要,將想要導出字段的名字首字母大寫,其他字段首字母小寫隱藏起來即可.
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
go實現(xiàn)grpc四種數(shù)據(jù)流模式
這篇文章主要為大家介紹了go實現(xiàn)grpc四種數(shù)據(jù)流模式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04