go语言的omitempty总结 | 青训营笔记

69 阅读2分钟

这是我参与「第五届青训营」笔记创作活动的第 10 天

在使用Golang的时候,不免会使用Json和结构体的相互转换,这时候常用的就是 json.Marshaljson.Unmarshal两个函数。

这时候在定义json结构体的时候,我们会用到omitempty这个字段,这个字段看似简单,但是却有很多小坑,这篇文章带你稍微研究一下他的用途和功能

Basic Usage

当我们设置json的struct的时候,会定义每个字段对一个json的格式,比如定义一个dog 结构体:

type Dog struct {
	Breed string
	WeightKg int
}

现在我们对他进行初始化,将其编码为JSON格式:

func main() {
	d := Dog{
		Breed:    "dalmation",
		WeightKg: 45,
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

则输出的结果为:

{"Breed":"dalmation","WeightKg":45}

现在假如有一个结构体变量我们没初始化,那么结果可能也会跟我们预期的不太一样:

func main() {
	d := Dog{
		Breed:    "pug",
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

输出的结果为:

{"Breed":"pug","WeightKg":0}

明显dog的weight是未知,而不是0,并不是我们想要的结果,我们更想要的结果是:

{"WeightKg":null}

为了实现这样的目的,我们这时候应该使用omitempty 变量来帮我们实现,当我们在Dog结构体加上这个tag的时候:

type Dog struct {
	Breed    string
	// The first comma below is to separate the name tag from the omitempty tag 
	WeightKg int `json:",omitempty"`
}

输出结果为:

{"Breed":"pug"}

现在WeightKg就被设置为默认零值(对于int应该为0,对于string应该为"", 指针的话应该为nil)。

不能单纯使用omitempty

当结构体相互嵌套的时候,那么omitempty就可能出现问题,比如:

type dimension struct {
	Height int
	Width int
	}

type Dog struct {
	Breed    string
	WeightKg int
	Size dimension `json:",omitempty"`
}

func main() {
	d := Dog{
		Breed: "pug",
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

输出结果为:

{"Breed":"pug","WeightKg":0,"Size":{"Height":0,"Width":0}}

我们已经使用omitempty标注的dimension还是显示了出来。这是因为结构体dimension不知道空值是什么,GO只知道简单结构体例如int,string,pointer 这种类型的空值,为了不显示我们没有提供值的自定义结构体,我们可以使用结构体指针:

type Dog struct {
	Breed    string
	WeightKg int
	// Now `Size` is a pointer to a `dimension` instance
	Size *dimension `json:",omitempty"`
}

运行结果为:

{"Breed":"pug","WeightKg":0}

为什么会这样呢?因为指针是基本类型啊,Golang知道他的空值是啥,所以就直接赋值为nil(指针类型的空值)。