常见用法
omitempty主要用于json 和 struct 之间的转换,忽略掉结构体结构体的0值元素
例如:
type Person struct {
Name string `json:"name"`
Constellation string `json:"constellation,omitempty"`
Age uint32 `json:"age"`
}
type PersonOmite struct {
Name string `json:"name"`
Constellation string `json:"constellation,omitempty"`
Age uint32 `json:"age"`
}
data := `{
"name": "zhang san",
"Age": 30
}`
per := new(Person)
json.Unmarshal([]byte(data), &per)
perBytes, _ := json.MarshalIndent(per, "", " ")
fmt.Printf("%s\n", string(perBytes))
perOm := new(PersonOmite)
json.Unmarshal([]byte(data), &perOm)
perOmBytes, _ := json.MarshalIndent(perOm, "", " ")
fmt.Printf("%s\n", string(perOmBytes))
//得到的结果
{
"name": "zhang san",
"constellation":"",
"age": 30
}
{
"name": "zhang san",
"age": 30
}
坑1
带来方便的同时,使用 omitempty
也有些小陷阱,一个是该关键字无法忽略掉嵌套结构体。还是拿地址类型说事,这回我们想要往地址结构体中加一个新 field 来表示经纬度,如果缺乏相关的数据,暂时可以忽略。新的结构体定义如下所示
type address struct {
Street string `json:"street"`
Ste string `json:"suite,omitempty"`
City string `json:"city"`
State string `json:"state"`
Zipcode string `json:"zipcode"`
Coordinate coordinate `json:"coordinate,omitempty"`
}
type coordinate struct {
Lat float64 `json:"latitude"`
Lng float64 `json:"longitude"`
}
读入原来的地址数据,处理后序列化输出,我们就会发现即使加上了 omitempty
关键字,输出的 json 还是带上了一个空的坐标信息
{
"street": "200 Larkin St",
"city": "San Francisco",
"state": "CA",
"zipcode": "94102",
"coordinate": {
"latitude": 0,
"longitude": 0
}
}
为了达到我们想要的效果,可以把坐标定义为指针类型,这样 Golang 就能知道一个指针的“空值”是多少了,否则面对一个我们自定义的结构, Golang 是猜不出我们想要的空值的。于是有了如下的结构体定义
type address struct {
Street string `json:"street"`
Ste string `json:"suite,omitempty"`
City string `json:"city"`
State string `json:"state"`
Zipcode string `json:"zipcode"`
Coordinate *coordinate `json:"coordinate,omitempty"`
}
type coordinate struct {
Lat float64 `json:"latitude"`
Lng float64 `json:"longitude"`
}
相应的输出为
{
"street": "200 Larkin St",
"city": "San Francisco",
"state": "CA",
"zipcode": "94102"
}
坑2
另一个“陷阱”是,对于用 omitempty
定义的 field ,如果给它赋的值恰好等于默认空值的话,在转为 json 之后也不会输出这个 field 。比如说上面定义的经纬度坐标结构体,如果我们将经纬度两个 field 都加上 omitempty
type coordinate struct {
Lat float64 `json:"latitude,omitempty"`
Lng float64 `json:"longitude,omitempty"`
}
然后我们对非洲几内亚湾的“原点坐标”非常感兴趣,于是编写了如下代码
func main() {
cData := `{
"latitude": 0.0,
"longitude": 0.0
}`
c := new(coordinate)
json.Unmarshal([]byte(cData), &c)
// 具体处理逻辑...
coordinateBytes, _ := json.MarshalIndent(c, "", " ")
fmt.Printf("%s\n", string(coordinateBytes))
}
最终我们得到了一个
{}
这个坐标消失不见了!但我们的设想是,如果一个地点没有经纬度信息,则悬空,这没有问题,但对于“原点坐标”,我们在确切知道它的经纬度的情况下,(0.0, 0.0)仍然被忽略了。正确的写法也是将结构体内的定义改为指针
type coordinate struct {
Lat *float64 `json:"latitude,omitempty"`
Lng *float64 `json:"longitude,omitempty"`
}
这样空值就从 float64
的 0.0 变为了指针类型的 nil
,我们就能看到正确的经纬度输出。
{
"latitude": 0,
"longitude": 0
}