个人学习总结,如有不对的地方也欢迎指出,一起交流学习,共同进步

结构体转Json

type Person1 struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
	Addr string `json:"addr"`
}
type Person2 struct {
	Name string `json:"name"`
	Age  int    `json:"age,omitempty"`
	Addr string `json:"addr"`
}

func main() {
	var ps Person1
	//var ps Person2
	ps.Name = "ming"
	ps.Addr = "Beijing"
	psByte, _ := json.Marshal(ps)
	fmt.Printf("%s\n", string(psByte))
}
omitempty零值
Person1: {"name":"ming","age":0,"addr":"Beijing"}
Person2: {"name":"ming","addr":"Beijing"}
omitempty

Json转结构体

omitempty
omitemptyjson.Unmarshal
Person: {"name": "ming", "addr": "Beijing"}
omitempty

这时候可以把这个字段定义成对应的指针类型,如下面结构体Person3的Addr字段

type Person3 struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
	Addr *string `json:"addr,omitempty"`
}

虽然json对象不管有没有"addr"这个键,得到的Person3对象都能够访问Addr字段,但可以通过比较Addr是否等于nil来判断json对象存不存在对应键,如果等于nil 则说明不存在,反之则存在。这里其实是利用了指针的零值为nil的特性。

添加omitempty的时机

对于一个指针类型的字段,无论是否添加omitempty字段,在不给该字段传值的情况,默认会被赋予一个空指针,依旧可以对这个结构体对象的该字段判断是否为空

其实就是对于一个结构体的字段而言,是否添加该字段只会影响到该结构体对象转化为json对象,添加了该字段,而恰好创建这个结构体对象时这个字段又没有传入值,那这个字段就会默认被赋予一个零值,然后再转换为json对象的时候这个字段就会被省略掉,使得展开jso对象的时候是看不到这个字段的。但并不会影响到这个结构体对象的使用,结构体的这个字段就是一个零值,类比的你可以想象创建一个空结构体对象的时候,那么所有字段都初始化为对应类型的零值了

int*int*string(指针)
type Book struct {
	Name   string  `json:"name"`
	Price  float32 `json:"price"`
	Desc   string  `json:"desc,omltempty"`
	Author  //匿名结构体
}
type Book2 struct {
	Name   string  `json:"name"`
	Price  float32 `json:"price"`
	Desc   string  `json:"desc,omitempty"`
	Author Author  `json:"author,omitempty"` //有名结构体
}
type Book3 struct {
	Name   string  `json:"name"`
	Price  float32 `json:"price"`
	Desc   string  `json:"desc,omitempty"`
	Author *Author `json:"author,omitempty"` //有名结构体(指针类型)
}
type Author struct {
	Gender int `json:"gender,omitempty"`
	Age    int `json:"age,Omitempty"`
}                                                

1)匿名结构体本质上更接近外层结构体的字段的一个集合,并不算结构体嵌套。

func main() {
	 var book Book 
	 book.Name = "testBook" 
	 bookByte, _ := json.Marshal(book) 
	 fmt.Printf("%s\n", string (bookByte)) 
}

对于上面的定义,在Gender和Age都没有赋值的情况下,输出的结果下面这样,但要注意的是,被忽略掉其实是"gender"和"age'"两个键而非"author"这个键,只要给Gender或者Age字段赋值,"gender"或"age"键就会显示出来,且和"name"、"price" 平级。

{"name":"testBook","price":0}

2)而有名结构体依旧可以按照两种方式去讨论,即原类型和指针类型

func main() {
	 var book Book 
	 book.Name = "testBook" 
	 bookByte, _ := json.Marshal(book) 
	 fmt.Printf("%s\n", string (bookByte)) 
}

比如原类型结果是这样

{"name":"testBook","price":0,"author":{}}

但指针类型的结果就会忽略掉"author"键

{"name":"testBook","price":0}
*ptr

总结来说就是下面几点

1)结构体转json时,如果希望某个字段不显式初始化(赋值)就不会存在对应的键,则加上0mitempty关键字

2)如果已经加上了omitempty关键字,但显示初始化(赋值)这个字段的数据又可能为该类型的零值,则需要考虑将这个字段转成对应的指针类型去处理,否则这 个字段即便传入了值,最后仍然会因为是零值而被忽略

3) json转结构体时,某个字段的值是零值(如int类型的字段数值为0),如果需要确定json对象是否存在这样一个键,则可以将这个字段转成对应的指针类型去处理