Go如何實現(xiàn)json字符串與各類struct相互轉換
json字符串與各類struct相互轉換
不廢話了都在代碼中了
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"` //導出對應json的字段名為currentHight
Class *Class `class` //指針,指向引用對象;如果不用指針,只是值復制
}
func doMarshal(){//對象轉json字符串
nClass:=new(Class)//new只給給特定類型分配內存,設置“零”值,返回其地址(指針)
fmt.Printf("nClass的類型是%s,內容是%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("轉json失?。?v\n",err1)
return
}
fmt.Println("轉成的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("轉jsonList失敗:%v\n",err2)
return
}
fmt.Println("轉成的列表型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字符串轉對象
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()//對象轉json字符串
doUnMarshal()
}簡單總結
1、結構體對象可生成json字符串,Marshal()是[]byte,需要string去轉換
2、json字符串可以映射到一個struct,但僅限公共元素(大寫開頭);也可通用的轉換到空接口interfece[],使用對應轉換到需要的內容
結構體轉換為JSON字符串的一個坑
通過json.Marshal來將結構體數(shù)據(jù)轉換為json字符串時,需要注意結構體內成員變量的首字母大小寫的問題,很容易會掉進坑里.
來看一下這個例子
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"}
可以看到轉換的json字符串中只包含了Name字段,age字段被忽略了.這是由于在進行json解析時,只會轉換結構體能夠導出的字段(首字母大寫),其他字段將會被忽略.
這個機制也有個好處,可以根據(jù)實際需要,將想要導出字段的名字首字母大寫,其他字段首字母小寫隱藏起來即可.
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
go實現(xiàn)grpc四種數(shù)據(jù)流模式
這篇文章主要為大家介紹了go實現(xiàn)grpc四種數(shù)據(jù)流模式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04

