脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go如何实现json字符串与各类struct相互转换

Go如何实现json字符串与各类struct相互转换

2022-08-30 19:52FeelTouch Labs Golang

这篇文章主要介绍了Go如何实现json字符串与各类struct相互转换,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

json字符串与各类struct相互转换

不废话了都在代码中了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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个参数必须是指针,否则报错: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来将结构体数据转换为json字符串时,需要注意结构体内成员变量的首字母大小写的问题,很容易会掉进坑里.

来看一下这个例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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解析时,只会转换结构体能够导出的字段(首字母大写),其他字段将会被忽略.

这个机制也有个好处,可以根据实际需要,将想要导出字段的名字首字母大写,其他字段首字母小写隐藏起来即可.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/feeltouch/article/details/124738603

延伸 · 阅读

精彩推荐