Go omitepty 使用

94 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

Go omitepty 使用

开发过程中,往往会用到 json.Marshaljson.Unmarshal两个函数。

omitemptyjson.Marshal 中可以赋予空值

使用omitempty,如果选择使用了他,那你就要第一时间知道,各个值的空值是什么?

如果不使用 omitempty这个字段,会发生啥?

type PersonAllow struct {
	Name     string
	Age      int64
	Birth    time.Time
	Children []PersonAllowEmpty
}

测试代码:

func TestMarshal_PersonAllow(t *testing.T) {
	person := PersonAllow{}
	jsonBytes := JsonMarshal(person)
	fmt.Println(string(jsonBytes)) // {"Birth":"0001-01-01T00:00:00Z"}
}

执行结果:

=== RUN   TestMarshal_PersonAllow
{"Name":"","Age":0,"Birth":"0001-01-01T00:00:00Z","Children":null}
--- PASS: TestMarshal_PersonAllow (0.00s)
PASS

如果加上 会怎么样?

type PersonAllowEmpty struct {
	Name     string             `json:",omitempty"`
	Age      int64              `json:",omitempty"`
	Birth    time.Time          `json:",omitempty"`
	Children []PersonAllowEmpty `json:",omitempty"`
}

测试代码:

func TestMarshalEmpty2(t *testing.T) {
	person := PersonAllowEmpty{}
	jsonBytes := JsonMarshal(person)
	fmt.Println(string(jsonBytes)) // {"Birth":"0001-01-01T00:00:00Z"}
}

执行结果:

=== RUN   TestMarshalEmpty2
{"Birth":"0001-01-01T00:00:00Z"}
--- PASS: TestMarshalEmpty2 (0.00s)
PASS

该关键字无法忽略掉嵌套结构体,当结构体相互嵌套的时候,那么omitempty就可能出现问题,比如:

type dimension struct {
	Height int
	Width  int
}

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

func TestOmitmpty(t *testing.T) {
	d := Dog{
		Breed: "pug",
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

执行结果:

=== RUN   TestOmitmpty
{"Breed":"pug","WeightKg":0,"Size":{"Height":0,"Width":0}}
--- PASS: TestOmitmpty (0.00s)
PASS

可以看到 omitempty似乎没有生效,这是因为结构体dimension空值其实就是 dimension{} , 我们改成指针试试。

type dimension struct {
	Height int
	Width  int
}

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

func TestOmitmpty(t *testing.T) {
	d := Dog{
		Breed: "pug",
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

执行结果:

=== RUN   TestOmitmpty
{"Breed":"pug","WeightKg":0}
--- PASS: TestOmitmpty (0.00s)
PASS

指针类型的空值为 nil, 直接赋值为nil(指针类型的空值)。

当我们的零值有特殊含义时,如果被忽略,会有问题, 比如经纬度 0,0 :

type coordinate struct {
	Lat float64 `json:"latitude,omitempty"`
	Lng float64 `json:"longitude,omitempty"`
}

func TestOmitmpty_1(t *testing.T) {
	d := coordinate{
		Lat: 0.0,
		Lng: 0.0,
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

执行结果:

=== RUN   TestOmitmpty_1
{}
--- PASS: TestOmitmpty_1 (0.00s)
PASS

如何解决,使用指针

type coordinate struct {
	Lat *float64 `json:"latitude,omitempty"`
	Lng *float64 `json:"longitude,omitempty"`
}

func TestOmitmpty_1(t *testing.T) {
	lat := 0.0
	lng := 0.0
	d := coordinate{
		Lat: &lat,
		Lng: &lng,
	}
	b, _ := json.Marshal(d)
	fmt.Println(string(b))
}

执行结果:

=== RUN   TestOmitmpty_1
{"latitude":0,"longitude":0}
--- PASS: TestOmitmpty_1 (0.00s)
PASS