Golang 的 “omitempty” 关键字略解
转载地址:Golang 的 “omitempty” 关键字略解
原文 :Golang 的 “omitempty” 关键字略解[1]
用法
熟悉 Golang 的朋友对于 json 和 struct 之间的转换一定不陌生,为了将代码中的结构体与 json 数据解耦,通常我们会在结构体的 field 类型后加上解释说明,例如在表示一个地址的时候, json 数据如下所示
{"street": "200 Larkin St","city": "San Francisco","state": "CA","zipcode": "94102"
}
与之相对应的 Golang 结构体表示定义如下
type address struct {Street string `json:"street"` // 街道Ste string `json:"suite"` // 单元(可以不存在)City string `json:"city"` // 城市State string `json:"state"` // 州/省Zipcode string `json:"zipcode"` // 邮编
}
这样无论代码中的变量如何改变,我们都能成功将 json 数据解析出来,获得正确的街道,城市等信息,到目前为止一切正常。但如果我们想要将地址结构体恢复成 json 格式时,问题就来了。比方说我们用下面这段代码读取了地址 json ,然后根据业务逻辑处理了之后恢复成正常的 json 打印出来
func main() {data := `{"street": "200 Larkin St","city": "San Francisco","state": "CA","zipcode": "94102"}`addr := new(address)json.Unmarshal([]byte(data), &addr)// 处理了一番 addr 变量...addressBytes, _ := json.MarshalIndent(addr, "", " ")fmt.Printf("%s\n", string(addressBytes))
}
可以得到运行结果
{"street": "200 Larkin St","suite": "","city": "San Francisco","state": "CA","zipcode": "94102"
}
多了一行 "suite": "",
,而这则信息在原本的 json 数据中是没有的(在美国的地址中,如果不是群租公寓或者共享办公楼, suite 这一条不存在很正常,人们直接用街道门牌号来表示地址就足够了),但我们更希望的是,在一个地址有 suite 号码的时候输出,不存在 suite 的时候就不输出,幸运的是,我们可以在 Golang 的结构体定义中添加 omitempty
关键字,来表示这条信息如果没有提供,在序列化成 json 的时候就不要包含其默认值。稍作修改,地址结构体就变成了
type address struct {Street string `json:"street"`Ste string `json:"suite,omitempty"`City string `json:"city"`State string `json:"state"`Zipcode string `json:"zipcode"`
}
重新运行,即可得到正确的结果。
陷阱
带来方便的同时,使用 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"
}
另一个“陷阱”是,对于用 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
}
Golang 的 “omitempty” 关键字略解相关推荐
- Java关键字详解-配视频讲解链接(附带一些面试题)
Java中常用的关键字详解-配视频讲解链接(附带一些面试题) 关键字:被Java赋予了特定含义的英文单词.关于关键字的学习贯穿了整个Java的学习,结合应用理解记忆关键字,不能单纯的死记硬背,在这里通 ...
- golang程序启动流程详解
golang程序启动流程详解 环境 go1.16.5 linux/amd64 用例 package mainimport "fmt"func main() {fmt.Println ...
- Java static静态关键字详解(public、 private、 volatile)
文章目录 前言 static要解决什么问题? 格式 特点 static静态变量 静态变量和实例变量的区别 static静态方法 static应用场景 static 与volatile static如何 ...
- Java中的static关键字详解
** Java中的static关键字详解 ** 在一个类中定义一个方法为static,即静态的,那就是说无需本类的对象就可以调用此方法.调用一个静态方法就是 "类名.方法名" ,静 ...
- Delphi 关键字详解[整理于 橙子 的帖子]
Delphi 关键字详解[整理于 "橙子" 的帖子] absolute //它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同. var Str: string[3 ...
- swift. 扩展类添加属性_swift中的声明关键字详解
原起 学习swift,swift中的关键字当然要了解清楚了,最近在网上看到了关于声明关键字的文章,整理记录一下. 关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符 ...
- C#关键字详解第二节
base:基类 在有些书中base的解释为表示父类,没错,base可以表示父类,但我更想理解成基类,因为更原始更具象,既然是类,那么他就符合面向对象的设计规则和特点,我们知道面向对象的三个特点是封装, ...
- C++ explicit关键字详解(用于构造函数)
C++ explicit关键字详解(用于构造函数) C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生.声明为explicit的构造函数不能在隐式转换中使用. ...
- C++/面试 - 四种类型转换(cast)的关键字 详解 及 代码
四种类型转换(cast)的关键字 详解 及 代码 本文原创, 禁止转载, 如有需要, 请站内联系. 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...
最新文章
- torch_{geometric/scatter}中一些函数的用法(softmax,scatter)
- MDT 2013 从入门到精通之SQL Computer Unattended Files
- 汇编-Hello,world
- 王高利:TCP Wrappers访问控制(hosts.allow,hosts.deny)
- c语言程序设计 银行整存整取,《C语言程序设计习题试题集》.doc
- Qt工作笔记-Qt连接Mysql数据库,检索及修改表数据
- (十一)Hibernate 高级配置
- 使用反射创建实例/对象的两种方法
- STM32——HAL版——串口发送字符串函数
- java检测按键,java-me – 如何以LWUIT形式检测按键事件?
- Centos 7安装Zabbix6.0
- oracle数据库查询904错误,EXP-00008:遇到ORACLE错误904问题详解
- CSS之九宫格面试题
- react中使用构建缓存_如何使用React,GraphQL和Okta构建健康跟踪应用
- 查看计算机bios版本,如何查看电脑BIOS版本
- Acwing-4645. 选数异或
- Greenplum助医疗大数据从“奢侈品”走向常态化
- unreal 用于三维展示的改造 建筑 模型展示
- JS中字符串的创建、操作及其方法
- 缩放图像、切割图像、图像类型转换、彩色转黑白、文字水印、图片水印