go的json序列化

go的json序列化

前言:

go语言的json序列化与反序列化借助的go语言的数据结构是 结构体(python中借助的是字典)

声明一个Movie结构体

type Movie struct {
  Title string
  Year   int  `json:"released"`
	Color  bool `json:"color,omitempty"`
	Actors []string
}

一、序列化(json.Marshal或json.MarshalIndent)

1、json.Marshal
// 先实例化一个结构体
var movies = []Movie{
		{Title: "Casablanca", Year: 1942, Color: false,
			Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
		{Title: "Cool Hand Luke", Year: 1967, Color: true,
			Actors: []string{"Paul Newman"}},
		{Title: "Bullitt", Year: 1968, Color: true,
			Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
	}
// struct -> json string 将结构体序列化为json 字符串
data, err := json.Marshal(movies)
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
	}
	fmt.Printf("%s\n", data)
// out

/*
[{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingrid Bergman"]},{"Title":"Cool Hand Luke","released":1967,"color":true,"Actors":["Paul Newman"]},{"Title":"Bullitt","released":1968,"color":true,"Actors":["Steve McQueen","Jacqueline Bisset"]}]

*/

Marshal 序列化后返回一个编码后的字节切片[]uint8,包含很长的字符串,没有空白缩进,这种紧凑的表现形式不便与阅读,所以使用MarshalIndent

2、json.MarshalIndent
data, err := json.MarshalIndent(movies, "", "    ")
if err != nil {
    log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)

// MarshalIndent(),需要三个参数,后两个额外的字符串参数 用于表示每一行输出的前缀和每一个层级的缩进,
输出:
[
    {
        "Title": "Casablanca",
        "released": 1942,
        "Actors": [
            "Humphrey Bogart",
            "Ingrid Bergman"
        ]
    },
    {
        "Title": "Cool Hand Luke",
        "released": 1967,
        "color": true,
        "Actors": [
            "Paul Newman"
        ]
    },
    {
        "Title": "Bullitt",
        "released": 1968,
        "color": true,
        "Actors": [
            "Steve McQueen",
            "Jacqueline Bisset"
        ]
    }
]

可能留意到了,json序列化编码后,原来的Year 和 Color 字段发生了变化,变成了released和color, 这是因为结构体成员 Tag导致的

Tag信息
Year   int  `json:"released"`
Color  bool `json:"color,omitempty"`

反引号里的Tag可以是任意的字符串面值,通常是一系列用空格分割的key:“value”键值对序列,因为值种含有双引号字符,因此tag一般使用原生字符串面值的形式书写。json开头键名对应的值用于控制encoding/json包的编码和解码的行为,并且encoding/…下面其它的包也遵循这个约定。成员Tag中json对应值的第一部分用于指定JSON对象的名字,序列化的结果就是结构体的字段名变为了json对象的名字,如go结构体的Year字段对应到JSON中的released对象,Color成员的Tag还带了一个额外的omitempty选项,表示当go语言结构体成员为空或零值时不生成json对象,电影Casablanca是一个黑白电影,并没有输出color成员。

二、反序列化(json.Unmarshal)

m1 := Movie{}
	json_str := `{
 "Title": "Casablanca",
  "released": 1942,
"color": true,
  "Actors": [
  "Humphrey Bogart",
  "Ingrid Bergman"
 ]
 }`
	err = json.Unmarshal([]byte(json_str), &m1)
// 只反序列化部分字段,选择性的解码json对象中的成员
	var released []struct{ Released   int }// 自返回发行时间
	var actor []struct{Actors []string}//只返回主演演员
	var titles []struct{ Title string } // 返回电影title
	var color []struct{ Color bool } // 返回电影颜色
	err = json.Unmarshal(data, &titles)
	err = json.Unmarshal(data, &released)
	err = json.Unmarshal(data, &actor)
	if err != nil {
		log.Fatalf("JSON unmarshaling failed: %s", err)
	}
	//fmt.Println(titles)
	fmt.Println(released)
	//fmt.Println(color)
	fmt.Println(actor)
	fmt.Println(m1)

编码的逆操作是解码,对应将json数据解码为go语言的数据结构,go语言的反序列化通过json.unmarshal()函数完成。注意,在反序列Tag中的json对象的时候,字段的名字必须是json的对象字段并要将json对象字段的首字母大写,才能反序列化成功

三、嵌套结构体序列化

//嵌套结构体序列化
type User struct {
   Name  string   `json:"name"`
   Email string   `json:"email,omitempty"`
   Hobby []string `json:"hobby,omitempty"`
   Profile 
}

type Profile struct {
   Website string `json:"site"`
   Slogan  string `json:"slogan"`
}
func nestedStructDemo() {
	u1 := User{
		Name:  "bob",
		Hobby: []string{"足球", "双色球"},
		//Profile:profile,
	}
	b, err := json.MarshalIndent(u1,""," ")
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v\n", err)
		return
	}
	fmt.Printf("str:%s\n", b)

}
// 序列化结果

/*
str:{
 "name": "bob",
 "hobby": [
  "足球",
  "双色球"
 ],
 "site": "",
 "slogan": ""
}

*/
1、变为双层嵌套的json串
type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
	Profile `json:"profile"`
}
// str:{"name":"bob","hobby":["足球","双色球"],"profile":{"site":"","slogan":""}}
2、忽略空值字段
type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
	Profile
}
// 给嵌套的结构体字段Tag增加 omiteempty 字段
type Profile struct {
	Website string `json:"site,omitempty"`
	Slogan  string `json:"slogan,omitempty"`
}
// 序列化输出结果
/*
str:{
 "name": "bob",
 "hobby": [
  "足球",
  "双色球"
 ]
}
*/

// 或者
type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
	*Profile  `json:"profile,omitempty"`
}
type Profile struct {
	Website string `json:"site"`
	Slogan  string `json:"slogan"`
}
// str:{"name":"bob","hobby":["足球","双色球"]}
3、不修改原结构体忽略空值字段
type Usr struct {
	Name     string `json:"name"`
	Password string `json:"password"`
}

type PublicUser struct {
	*Usr
	// 匿名嵌套
	Password *struct{} `json:"password,omitempty"`
}

func omitPasswordDemo()  {
	u1 := Usr{Name:"bob",Password:"123"}
	p := PublicUser{Usr:&u1}
	u,_ := json.Marshal(p)
	fmt.Printf("str:%s\n",u)
}
// 本质就是借助匿名嵌套,并添加了omitempty,当空值时不序列化

四、关于json tag字段的反序列化

  1. 关于字段可见性:序列化和反序列化本质上是两个包的数据之间的转化,一个是自己写的包,就是自己写的代码所在的包,另一个就是json包
    而go语言的一个包之间的关键特性就是 类型变量首字母大写才能对外可见,所以在涉及序列化和反序列化时,必须将字段首字母大写
  2. 关于前后端交互:如果必须得用全小写,那么就使用 go语言的tag标签功能,tag的格式需严格执行:即 反引号``,将键值对扩起来,里面的值要用双引号扩起来,
    如果是多个tag,之间用《空格》隔开。
  3. 反序列化的格式:json.Unmarshal([]byte(jsonStr),&c2),括号里的是byte类型的数组,和结构体的指针。
  4. 反序列化时,对于go结构体中有Tag对应的json对象的,存放反序列化的结构体中的字段必须为json对象的字段,并且首字母大写,不然无法实现反序列化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值