Go语言omitempty选项的实现
在使用Golang的时候,不免会使用Json和结构体的相互转换,这时候常用的就是 json.Marshal 和 json.Unmarshal 两个函数。这时候在定义json结构体的时候,我们会用到 omitempty 这个字段,这个字段作用就是 空值省略,看似简单,但是却有很多小坑,这篇文章带你稍微研究一下他的用途和功能。
omit:
v. 删除; 忽略; 漏掉; 遗漏; 不做; 未能做;
adj. 省略了的;省去的;
基本用法
当我们设置json的struct的时候,会定义每个字段对一个json的格式,比如定义一个dog 结构体:
type Dog struct { Name string Weight int }
现在我们对他进行初始化,将其编码为JSON格式:
func main() { d := Dog{ Name: "小黑", Weight: 20, } marshalDog, err := json.Marshal(d) if err != nil { fmt.Println(err.Error()) } fmt.Println(string(marshalDog)) }
则输出的结果为:
{"Name":"小黑","Weight":20}
现在假如有一个结构体变量我们没初始化,那么结果可能也会跟我们预期的不太一样:
d := Dog{ Name: "小黑", }
输出的结果为:
{"Name":"小黑","Weight":0}
很明显,狗的weight是未知,而不是0,并不是我们想要的结果,我们更想要的结果是:
{"Name":"小黑"}
为了实现这样的目的,我们这时候应该使用 omitempty 选项来帮我们实现,当我们在Dog结构体加上这个tag的时候:
type Dog struct { Name string Weight int `json:",omitempty"` }
此时,输出结果为:
{"Name":"小黑"}
不能单纯使用omitempty
当结构体相互嵌套的时候,那么omitempty就可能出现问题,比如:
type Variety struct { Color string Category string } type Dog struct { Name string Weight int `json:",omitempty"` Variety Variety `json:",omitempty"` } func main() { d := Dog{ Name: "小黑", } marshalDog, err := json.Marshal(d) if err != nil { fmt.Println(err.Error()) } fmt.Println(string(marshalDog)) }
输出结果为:
{"Name":"小黑","Variety":{"Color":"","Category":""}}
omitempty 为什么对嵌套结构体不生效呢?这是因为GO只知道简单结构体例如int,string,pointer 这种类型的空值,不知道Variety类型的空值是什么,为了不显示我们没有提供值的自定义结构体,我们可以使用结构体指针:
type Dog struct { Name string Weight int `json:",omitempty"` Variety *Variety `json:",omitempty"` }
运行结果为:
{"Name":"小黑"}
但是如果给出下面情况的赋值:
d := Dog{ Name: "小黑", Variety: &Variety{Color: "black"}, }
运行结果为:
{"Name":"小黑","Variety":{"Color":"black","Category":""}}
可以看到,omitempty只对*Variety生效。所以想要嵌套结构体里面的字段也能有空值省略的效果,就要在定义嵌套的结构体的时候,对里面的每个字段都要加上omitempty选项。如下所示:
type Variety struct { Color string `json:",omitempty"` Category string `json:",omitempty"` }
运行结果如下:
{"Name":"小黑","Variety":{"Color":"black"}}
剩下的最后一个坑就是:如果想要某个值就是为空(有实际意义),也就是说当一个空值有实际意义的时候就显示,没有实际意义(当时还不知道其值)的时候就不显示,这样的需求应该怎么做?如果还是向上面那样,当我们需要Category为空的时候(Category:“”),最后会发现omitempty选项会把这个空值字段省略。正确的做法是使用指针来定义其变量。最后代码如下:
package main import ( "encoding/json" "fmt" ) type Variety struct { Color *string `json:",omitempty"` Category *string `json:",omitempty"`//一定要是*string类型 } type Dog struct { Name string Weight int `json:",omitempty"` Variety *Variety `json:",omitempty"` } func main() { color := "black" //此处的空值有实际意义 category := "" d := Dog{ Name: "小黑", Variety: &Variety{Color: &color, Category: &category}, } marshalDog, err := json.Marshal(d) if err != nil { fmt.Println(err.Error()) } fmt.Println(string(marshalDog)) }
运行结果如下:
{"Name":"小黑","Variety":{"Color":"black","Category":""}}
到此这篇关于Go语言omitempty选项的实现的文章就介绍到这了,更多相关Go语言omitempty选项内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Go for-range 的 value值地址每次都一样的原因解析
循环语句是一种常用的控制结构,在 Go 语言中,除了 for 关键字以外,还有一个 range 关键字,可以使用 for-range 循环迭代数组、切片、字符串、map 和 channel 这些数据类型,这篇文章主要介绍了Go for-range 的 value值地址每次都一样的原因解析,需要的朋友可以参考下2023-05-05
最新评论