go json omitempty 关键字 脱坑
用法
大家对于 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
}
go json omitempty 关键字 脱坑的更多相关文章
- 大数据 SQL Boy 脱坑指南
不可否认的是 SQL 是一个伟大的发明,它让增删改查的操作更加地便捷化,而且 SQL 的学习成本相对其他编程语言来说较低,被逼到会写 SQL 的运营和产品我都见过不少... 大数据行业跟 SQL 更是 ...
- pandas处理json脱坑(二)--jsonError: Expecting ',' delimiter: line 1 column 2674
Expecting ',' delimiter: line 1 column 2674 json_dict = json.loads(row[json_columns].replace("' ...
- pandas处理json脱坑(一)--JsonError: Expecting property name enclosed in double quotes
python执行json.loads(…)时遇到的错误json格式的文本中应该用双引号,而不是单引号,如: brief=json.loads(row["brief"].replac ...
- 【转】Vue 脱坑记 - 查漏补缺(汇总下群里高频询问的xxx及给出不靠谱的解决方案)
前言 文章内容覆盖范围,芝麻绿豆的破问题都有,不止于vue; 给出的是方案,但不是手把手一字一句的给你说十万个为什么! 有三类人不适合此篇文章: “喜欢站在道德制高点的圣母婊” – 适合去教堂 “无理 ...
- Vue 脱坑记 - 查漏补缺(汇总下群里高频询问的xxx及给出不靠谱的解决方案)
前言 发现群里有些问题的提问重复率太高了,每次都去回答,回答的贼烦.这里做一个大体的汇总,废话不多说,直接开始给出方案,不是手把手..若是连问题和解决都看不懂的..应该去补充下基础知识 问题汇总 Q: ...
- Vue 脱坑记
问题汇总 Q:安装超时(install timeout) 方案有这么些: cnpm : 国内对npm的镜像版本 /* cnpm website: https://npm.taobao.org/ */ ...
- python中json.dumps使用的坑以及字符编码
我们知道,python中的字符串分普通字符串和unicode字符串,一般从数据库中读取的字符串会自动被转换为unicode字符串 下面回到重点,使用json.dumps时,一般的用法为: >&g ...
- nodejs request module里的json参数的一个坑
今天工作的时候遇到一个坑,在客户端用nodejs给服务器发送HTTP请求,服务器老是报错:In the context of Data Services an unknown internal ser ...
- MongoDB数据实体中的ObjectId序列化成json的一个小坑
很多时候我们都需要对实体对象进行序列化与反序列化,而ObjectId类型,只能用mongo的驱动以bson格式来序列化,但我们对外的交互,一般是json格式. 有两种解决方案: 1.自己写一个json ...
- Struts2返回json格式数据踩坑记录
事件起因 昨天提测修改冻结/解冻银行卡样式的功能,微姐测试过程中发现调用ajax请求耗时过长,今天来排查,发现浏览器请求/finance/ajax/freeze/ajaxGetShopLists时,对 ...
随机推荐
- Qt编写可视化大屏电子看板系统30-模块8物料管理
一.前言 物料管理模块包括库存占比.主要零件库存状况子模块,其中库存占比采用自定义控件环形进度条展示,总共有多种库存,具体根据数据库中的名称展示不同的界面,当库存数不够的时候,对应环形进度条颜色红色显 ...
- Windows上使用CMake GUI编译开源代码时,提示:cmake Could NOT find ZLIB (missing:ZLIB_LIBRARY)和Could NOT find PNG (missing: PNG_LIBRARY PNG_PNG_INCLUDE_DIR)的处理办法
有的时候就算在CMake GUI中配置完ZLIB_LIBRARY和PNG_LIBRARY和PNG_PNG_INCLUDE_DIR等相关路径,还是提示上述错误.原因还是由于编译某源码时遗漏了对第三方开源 ...
- postgresql-10.12-2-windows-x64安装成功后在安装postgis-bundle-pg96x64-setup-2.5.3-1时提示Spatial database creation failed
问题描述: postgresql-10.12-2-windows-x64安装成功后在安装postgis-bundle-pg96x64-setup-2.5.3-1时提示Spatial database ...
- IM通讯协议专题学习(二):快速理解Protobuf的背景、原理、使用、优缺点
本文由vivo技术团队Li Guanyun分享,为了提升阅读体验,进行了较多修订和重新排版. 1.引言 Protobuf 作为一种跨平台.语言无关.可扩展的序列化结构数据通讯协议,已广泛应用于网络数据 ...
- 自动化滑动极验v3示例
import random import ddddocr from playwright.sync_api import sync_playwright import time import requ ...
- unity assetbundle 加载图集的所有sprite图片
在 Unity 中,使用 AssetBundle 加载图集(Atlas)并获取其中的所有 Sprite 图片,通常需要以下步骤: 1. 打包图集到 AssetBundle 首先,确保你的图集(At ...
- 简单了解RPC实现原理-copy
核心框架类 /* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and pr ...
- 2020年最新网络编程面试题-copy
计算机网络体系结构 在计算机网络的基本概念中,分层次的体系结构是最基本的.计算机网络体系结构的抽象概念较多,在学习时要多思考.这些概念对后面的学习很有帮助. 网络协议是什么? 在计算机网络要做到有条不 ...
- Linux操作系统基础知识
一.输入法的切换Application ----> System Tools ----> Settings ----> Rejino&language ----> In ...
- Java 链表API
Java 链表 1.什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的. 每一个链表都包含多个节点,节点又包含两个部分: 1)一个是数据 ...