GO JSON序列化和反序列化
JSON格式
JSON语法检查网址: www.json.cn
如下所示,JSON的键值对的键必须以""双引号包裹,也就是key的类型必须是string,而val则随意。
[
{
"name":"小花",
"age":"10",
"adderss":"中国"
},
{
"name":"小刘",
"age":10,
"address":[
0,
1
]
}
]
序列化
对上面的json数据,为了在go语言中构造,我们使用了[]map[string]interface这种slice,就能够得到上述一致的内容
package main
import (
"encoding/json"
"fmt"
)
func main(){
jsonSlice:=make([]map[string]interface{},0)
jsonSlice=append(jsonSlice,make(map[string]interface{}))
jsonSlice[0]["name"]="小花"
jsonSlice[0]["age"]="10"
jsonSlice[0]["address"]="中国"
jsonSlice=append(jsonSlice,make(map[string]interface{}))
jsonSlice[1]["name"]="小刘"
jsonSlice[1]["age"]=10
jsonSlice[1]["address"]=[]int{0,1}
jsonString,err:=json.Marshal(jsonSlice)
if err!=nil{
fmt.Println("error")
}
fmt.Println(string(jsonString))
}
输出
[{"address":"中国","age":"10","name":"小花"},{"address":[0,1],"age":10,"name":"小刘"}]
但是由于map可能存在不同的顺序(后文运行结果好像为字典序),所以输出顺序和上面json输出的不一样,因此我们可以使用结构体来构造,得到一致的顺序
注意
Stuct中只有导出字段(首字母大写的)才可以转换为json,未导出的会被忽略!!!
package main
import (
"encoding/json"
"fmt"
)
type person struct {
Name string
Age interface{}
Address interface{}
id string
}
func main(){
jsonSlice:=make([]*person,0)
jsonSlice=append(jsonSlice,&person{"小花","10","中国","12345"})
jsonSlice=append(jsonSlice,&person{"小刘",10,[]int{0,1},"007"})
jsonString,err:=json.Marshal(jsonSlice)
if err!=nil{
fmt.Println("error")
}
fmt.Println(string(jsonString))
}
输出
[{"Name":"小花","Age":"10","Address":"中国"},{"Name":"小刘","Age":10,"Address":[0,1]}]
如上输出,结构体里的id没有输出,我们可以把这个认为是私有的
序列化中key-val的对应关系
- 普通类型
在对非key-value这种对应关系的变量,如int,float,序列化以后也就只是转字符串而已,并不会按照键值对那样对应,这样得到的结果是没有意义的
- 结构体
把成员变量名当成key,成员变量的值当成val
使用tag来设置导出的key不是成员变量名
比如,中国人喜欢中文,那么将key设置为中文不是更容易理解
package main
import (
"encoding/json"
"fmt"
)
type person struct {
Name string `json:"名字"`
Age interface{} `json:"年龄"`
Address interface{} `json:"地址"`
id string
}
func main(){
jsonSlice:=make([]*person,0)
jsonSlice=append(jsonSlice,&person{"小花","10","中国","12345"})
jsonSlice=append(jsonSlice,&person{"小刘",10,[]int{0,1},"007"})
jsonString,err:=json.Marshal(jsonSlice)
if err!=nil{
fmt.Println("error")
}
fmt.Println(string(jsonString))
}
输出
[{"名字":"小花","年龄":"10","地址":"中国"},{"名字":"小刘","年龄":10,"地址":[0,1]}]
- map
key-val一致
反序列化
将json字符串反序列化为go中的类型
仍然以开头的json字符串为例,分别反序列化为[]map[string]interface和[]struct
下面引入了两种map,看看分别转换的情况
package main
import (
"encoding/json"
"fmt"
)
func main(){
jsonString:=`[{"name":"小花","age":"10","address":"中国"},{"name":"小刘","age":10,"address":[0,1]}]`
var p1 []map[string]interface{}
err:=json.Unmarshal([]byte(jsonString),&p1)
if err!=nil{
fmt.Println("p1:",err)
}
fmt.Println("p1:",p1)
var p2 []map[int]interface{}
err=json.Unmarshal([]byte(jsonString),&p2)
if err!=nil{
fmt.Println("p2:",err)
}
fmt.Println("p2:",p2)
}
输出
p1: [map[address:中国 age:10 name:小花] map[address:[0 1] age:10 name:小刘]]
p2: json: cannot unmarshal number name into Go value of type int
p2: [map[] map[]]
由此可见,map的key类型是必须固定的,固定为string类型,否则就会报错
下面分别引入了不同的结构体,通过输出说明什么样的结构体才能成功的反序列化
package main
import (
"encoding/json"
"fmt"
)
type person1 struct {
Name string
Age interface{}
Address interface{}
}
type person2 struct {
name string
age interface{}
address interface{}
}
type person3 struct {
Naem string
Age interface{}
Address interface{}
}
type person4 struct {
Name string
Age interface{}
Address interface{}
Id string
}
type person5 struct {
Name int
Age interface{}
Address interface{}
id string
}
func main(){
jsonString:=`[{"name":"小花","age":"10","address":"中国"},{"name":"小刘","age":10,"address":[0,1]}]`
var p1 []person1
err:=json.Unmarshal([]byte(jsonString),&p1)
if err!=nil{
fmt.Println("p1:",err)
}
fmt.Println("p1:",p1)
var p2 []person2
err=json.Unmarshal([]byte(jsonString),&p2)
if err!=nil{
fmt.Println("p2:",err)
}
fmt.Println("p2:",p2)
var p3 []person3
err=json.Unmarshal([]byte(jsonString),&p3)
if err!=nil{
fmt.Println("p3:",err)
}
fmt.Println("p3:",p3)
var p4 []person4
err=json.Unmarshal([]byte(jsonString),&p4)
if err!=nil{
fmt.Println("p4:",err)
}
fmt.Println("p4:",p4)
var p5 []person5
err=json.Unmarshal([]byte(jsonString),&p5)
if err!=nil{
fmt.Println("p5:",err)
}
fmt.Println("p5:",p5)
}
输出
p1: [{小花 10 中国} {小刘 10 [0 1]}]
p2: [{ <nil> <nil>} { <nil> <nil>}]
p3: [{小花 10 中国} {小刘 10 [0 1]}]
p31: [{小花 10 中国} {小刘 10 [0 1]}]
p4: [{小花 10 中国 } {小刘 10 [0 1] }]
p5: json: cannot unmarshal string into Go struct field person5.Name of type int
p5: [{0 10 中国 } {0 10 [0 1] }]
person1是绝对合法的,
person2未导出所以就不能反序列化成功,但是不会报错,
person3的Naem,导致一个key不匹配,所以就忽略这个字段,不报错
person31的Naem虽然不匹配,但是tag是匹配的,所以会使用这个字段进行匹配
person4多了一个字段,所以也忽略这个字段,不报错
person5的Name类型是int类型,和json字符串中的string类型是不符合的,会报错
总结
- 序列化和反序列化包为encoding/json
- 函数可以使用Marshal和Unmarshal
- 理论上go里面的所有类型都可以序列化,但是结构体,map序列化较有意义
- 结构体的非导出字段不进行序列化
- 结构体如果定义了tag,那么序列化的key就是tag
- 反序列化一定要注意字段的类型匹配,否则会报错;
- 结构体的非导出字段不进行反序列化
- 名称不匹配的结构体或结构体中多出的字段会忽略,不报错
- 结构体中如果定义了tag,那么反序列化的key也会和tag进行匹配
本文链接:https://WinterStarHu.github.io/post/go-json-xu-lie-hua-he-fan-xu-lie-hua/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!