go学习-结构体与JSON序列化

摘要:
结构和JSON序列化JSON数据和结构相互转换基本序列化:JSON。Marshal()(序列化:结构-->JSON格式的字符串)和JSON反序列化(反序列化:JSON格式的串--&gt,结构)packagemainimport(“fmt”“encoding/JSON”)//学生类型Studentsstruct{IDintGenderstringN

结构体与JSON序列化

JSON数据与结构体之间相互转换
基本的序列化:json.Marshal()(序列化:结构体-->JSON格式的字符串)与json.Unmarshal(反序列化:JSON格式的字符串-->结构体)

package main

import ("fmt"
"encoding/json"
)

//Student 学生
type Student struct {
	ID     int
	Gender string
	Name   string
}

//Class 班级
type Class struct {
	Title    string
	Students []*Student
}

func main() {
	c := &Class{
		Title:    "101",
		Students: make([]*Student, 0, 200),
	}
	for i := 0; i < 10; i++ {
		stu := &Student{
			Name:   fmt.Sprintf("stu%02d", i),
			Gender: "男",
			ID:     i,
		}
		c.Students = append(c.Students, stu)
	}
	//JSON序列化:结构体-->JSON格式的字符串
	data, err := json.Marshal(c)
	if err != nil {
		fmt.Println("json marshal failed")
		return
	}
	fmt.Printf("json序列化结果:%s
", data)
	//JSON反序列化:JSON格式的字符串-->结构体
	str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
	c1 := &Class{}
	err = json.Unmarshal([]byte(str), c1)
	if err != nil {
		fmt.Println("json unmarshal failed!")
		return
	}
	fmt.Printf("json反序列化结果:%#v
", c1)
}

go学习-结构体与JSON序列化第1张

结构体标签(Tag)

Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。 Tag在结构体字段的后方定义,由一对反引号包裹起来,
具体的格式如下:
key1:"value1" key2:"value2"

注意事项: 为结构体编写Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在key和value之间添加空格。

使用json tag指定字段名

序列化与反序列化默认情况下使用结构体的字段名,我们可以通过给结构体字段添加tag来指定json序列化生成的字段名。

package main

import ("fmt"
"encoding/json"
)

// 使用json tag指定序列化与反序列化时的行为
//Student 学生
type Student struct {
	ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的key,指定json序列化/反序列化时使用小写id
	Gender string //json序列化是默认使用字段名作为key
	name   string //私有不能被json包访问
}
func main() {
	s1 := Student{
		ID:     1,
		Gender: "男",
		name:   "沙河娜扎",
	}
	data, err := json.Marshal(s1)
	if err != nil {
		fmt.Println("json marshal failed!")
		return
	}
	fmt.Printf("json str:%s
", data) //json str:{"id":1,"Gender":"男"}
	fmt.Printf("%#v
", s1) //main.Student{ID:1, Gender:"男", name:"沙河娜扎"}
}

go学习-结构体与JSON序列化第2张

忽略某个字段

如果你想在json序列化/反序列化的时候忽略掉结构体中的某个字段,可以按如下方式在tag中添加-。

// 使用json tag指定json序列化与反序列化时的行为
type Person struct {
	Name   string `json:"name"` // 指定json序列化/反序列化时使用小写name
	Age    int64
	Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段
}
忽略空值字段

当 struct 中的字段没有值时, json.Marshal() 序列化的时候不会忽略这些字段,而是默认输出字段的类型零值(例如int和float类型零值是 0,string类型零值是"",对象类型零值是 nil)。
如果想要在序列序列化时忽略这些没有值的字段时,可以在对应字段添加omitempty tag。
例如:没有添加omitempty

package main

import ("fmt"
"encoding/json"
)

type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email"`
	Hobby []string `json:"hobby"`
}
func main() {
	u1 := User{
		Name: "七米",
	}
	// struct -> json string
	b, err := json.Marshal(u1)
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v
", err)
		return
	}
	fmt.Printf("str:%s
", b)
}

go学习-结构体与JSON序列化第3张

添加omitempty:序列化结果中没有email和hobby字段

package main

import ("fmt"
"encoding/json"
)

type User struct {
	Name  string   `json:"name,omitempty"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
}
func main() {
	u1 := User{
		Name: "七米",
	}
	// struct -> json string
	b, err := json.Marshal(u1)
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v
", err)
		return
	}
	fmt.Printf("str:%s
", b)
}

go学习-结构体与JSON序列化第4张

结构体和方法补充知识点

因为slice和map这两种数据类型都包含了指向底层数据的指针,因此我们在需要复制它们时要特别注意。

package main

import ("fmt"
)

type Person struct {
	name   string
	age    int8
	dreams []string
}
func (p *Person) SetDreams(dreams []string) {
	p.dreams = dreams
}

func main() {
	p1 := Person{name: "小王子", age: 18}
        p2 := Person{name: "小王子2", age: 20}
	data := []string{"吃饭", "睡觉", "打豆豆"}
	p1.SetDreams(data)
        // 你真的想要修改 p1.dreams 吗?
	data[1] = "不睡觉"
	p2.SetDreams(data)
	
	fmt.Println(p1.dreams)  // 不想改变
        fmt.Println(p2.dreams)  // 想改变
}

结果:p1的内容也改变了。而我们真正想改变的只有p2的内容,不想改变p1
go学习-结构体与JSON序列化第5张
正确的做法是在方法中使用传入的slice的拷贝进行结构体赋值。
这样就会只改变副本,而不会全部改变
原因:由于切片和map是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。
Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,改变一个值,另一个的值就不会变化了。因为地址不同了。

func (p *Person) SetDreams(dreams []string) {
	p.dreams = make([]string, len(dreams))//动态创建长度为dreams的切片
	copy(p.dreams, dreams)//将dreams拷贝到p.dreams(另一个空间,不共用一个地址)
}

go学习-结构体与JSON序列化第6张

免责声明:文章转载自《go学习-结构体与JSON序列化》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇8组Beta冲刺总结英文投稿的一点经验【转载】下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

asp.net中序列化和反序列化json的两种常用方式

使用System.Web.Script.Serialization.JavaScriptSerializer类       JavaScriptSerializer类为.net类库自带,.net3.5及以后版本都可以使用,该类位于System.Web.Extensions.dll中,如需使用该类,必须添加引用。      (1) 序列化 p...

Ext Js简单Grid创建使用及AJAX处理

在使用Ext Js对于Grid组件使用必不可少的,对于它的掌握也是需要的。简单贴一些代码,看看Grid的创建使用,就不细讲每一步了,代码注释还可以,不明白的可以在评论中写一下,或发邮件给我,一定帮助解答,欢迎交流。1.简单Ext JsGrid的创建使用(创建Ext.grid.GridPanel需要store(proxy\reader)\colModel)...

XML文件与实体类的互相转换

一.将XML文件反序列化为实体类对象   1. 通常程序的配置信息都保存在程序或者网站的专门的配置文件中(App.config/web.config)。但是现在为了演示XML序列化和反序列化,将配置信息保存在一个XML文件(config.xml)中,通过反序列化将配置信息读取出来保存到一个单独的类(Config.cs)中。这样如果需要用到配置信息,没必要每...

XML、Linq、序列化、反射、XSLT在测试报告统计工具中的应用 Anny

客户要求对XML格式的测试结果进行统计,并发送出特定格式的邮件。 1. 测试结果有两种文件,一种是以xml为后缀的xml格式文件,一种是VS里跑测试用例产生的以trx为后缀的xml格式文件。 2. 每个文件里包含多个测试用例,每个测试用例有对应的Owner和归属类别Area。 3. 最后输出的报告格式如下: Area File Owner Pass F...

DRF的序列化组件

restrest下的url url唯一代表资源,http请求方式来区分用户行为 url的设计规范 GET: 127.0.0.1:9001/books/        # 获取所有数据 GET: 127.0.0.1:9001/books/{id}      # 获取单条数据 POST: 127.0.0.1:9001/books/      # 增加数据 D...

C# 序列化与反序列化之DataContract与xml对子类进行序列化的解决方案

C# 序列化与反序列化之DataContract与xml对子类进行序列化的解决方案 1、DataContract继承对子类进行序列化的解决方案 第一种是在 [DataContract, KnownType(typeof(继承的子类))]添加 KnownType(typeof(继承的子类))即可,第二种是在序列化的时候,添加类型 DataContractSe...