Go Json 序列化 omitempty 空值与隐藏字段的兼容

警告
本文最后更新于 2023-07-17,文中内容可能已过时。

omitempty

Go 语言提供了一个非常好用的 Json Tag:omitempty,它能在 Json 序列化时忽略空值,比如这样:

1
2
3
4
5
type user struct {
	Id    int64  `json:"id"`
	Name  string `json:"name,omitempty"`
	Age   int64  `json:"age,omitempty"`
}

在这里,我们设计了一个用户对象,我们对它做 Json 序列化就会发现 Go 忽略了空值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func main() {
    user := &user{
		Id:    1,
		Name:  "",
		Age:   0,
	}

	marshal, _ := json.Marshal(user)
	log.Println(string(marshal))  // {"id":1}
}

哪里出了问题?

可问题是,整型的空值、字符串的空值是有意义的,在某些业务场景下不能忽略。

如果业务方这样要求一个 Json 字段:

  • “0值”有意义,不可以隐藏。
  • 字段为可选(在某些情况下需要隐藏整个字段

这就产生了矛盾,如果想满足需求一则不能使用 omitempty,而需求二又需要用到 omitempty。此时,omitempty 隐藏“0值”字段的特性就会与需求产生巨大冲突,那该如何解决呢?

解决方案

我们可以利用指针的“0值”为 nil解决这个问题:将user对象的内置类型更换为指针类型:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
type user struct {
	Id    int64   `json:"id"`
	Name  *string `json:"name,omitempty"`  // 变为指针类型
	Age   *int64  `json:"age,omitempty"`
}

func main() {
	name := ""
	age := int64(0)

	user := &user{
		Id:   1,
		Name: &name,
		Age:  &age,
	}

	marshal, _ := json.Marshal(user)
	log.Println(string(marshal))  // {"id":1,"name":"","age":0}
}

可以看到,使用这种方式,即便有 omitempty 也能显示“0值”,符合需求一。

此外,如果想隐藏某个字段,可以将元素赋值为 nil:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
	age := int64(0)

	user := &user{
		Id:   1,
		Name: nil,
		Age:  &age,
	}

	marshal, _ := json.Marshal(user)
	log.Println(string(marshal))  // {"id":1,"age":0}
}

根据输出的结果可知,Name 字段被隐藏掉了,满足需求二。

总结

我们利用 Go 语言中指针的“0值”为 nil巧妙的解决了“隐藏字段”与 omitempty 的冲突。

问题虽然解决了,不过这真算不上优雅~如果你有更好的方式欢迎下方评论区留言。(说不定,Go 就是这么挫,逃~


转载声明:本文允许转载,原文地址:Go Json 序列化 omitempty 空值与隐藏字段的兼容

Buy me a coffee~
室长 支付宝支付宝
室长 微信微信
0%