转载地址: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” 关键字略解相关推荐

  1. Java关键字详解-配视频讲解链接(附带一些面试题)

    Java中常用的关键字详解-配视频讲解链接(附带一些面试题) 关键字:被Java赋予了特定含义的英文单词.关于关键字的学习贯穿了整个Java的学习,结合应用理解记忆关键字,不能单纯的死记硬背,在这里通 ...

  2. golang程序启动流程详解

    golang程序启动流程详解 环境 go1.16.5 linux/amd64 用例 package mainimport "fmt"func main() {fmt.Println ...

  3. Java static静态关键字详解(public、 private、 volatile)

    文章目录 前言 static要解决什么问题? 格式 特点 static静态变量 静态变量和实例变量的区别 static静态方法 static应用场景 static 与volatile static如何 ...

  4. Java中的static关键字详解

    ** Java中的static关键字详解 ** 在一个类中定义一个方法为static,即静态的,那就是说无需本类的对象就可以调用此方法.调用一个静态方法就是 "类名.方法名" ,静 ...

  5. Delphi 关键字详解[整理于 橙子 的帖子]

    Delphi 关键字详解[整理于 "橙子" 的帖子] absolute //它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同. var Str: string[3 ...

  6. swift. 扩展类添加属性_swift中的声明关键字详解

    原起 学习swift,swift中的关键字当然要了解清楚了,最近在网上看到了关于声明关键字的文章,整理记录一下. 关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符 ...

  7. C#关键字详解第二节

    base:基类 在有些书中base的解释为表示父类,没错,base可以表示父类,但我更想理解成基类,因为更原始更具象,既然是类,那么他就符合面向对象的设计规则和特点,我们知道面向对象的三个特点是封装, ...

  8. C++ explicit关键字详解(用于构造函数)

    C++ explicit关键字详解(用于构造函数) C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生.声明为explicit的构造函数不能在隐式转换中使用. ...

  9. C++/面试 - 四种类型转换(cast)的关键字 详解 及 代码

    四种类型转换(cast)的关键字 详解 及 代码 本文原创, 禁止转载, 如有需要, 请站内联系. 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...

最新文章

  1. torch_{geometric/scatter}中一些函数的用法(softmax,scatter)
  2. MDT 2013 从入门到精通之SQL Computer Unattended Files
  3. 汇编-Hello,world
  4. 王高利:TCP Wrappers访问控制(hosts.allow,hosts.deny)
  5. c语言程序设计 银行整存整取,《C语言程序设计习题试题集》.doc
  6. Qt工作笔记-Qt连接Mysql数据库,检索及修改表数据
  7. (十一)Hibernate 高级配置
  8. 使用反射创建实例/对象的两种方法
  9. STM32——HAL版——串口发送字符串函数
  10. java检测按键,java-me – 如何以LWUIT形式检测按键事件?
  11. Centos 7安装Zabbix6.0
  12. oracle数据库查询904错误,EXP-00008:遇到ORACLE错误904问题详解
  13. CSS之九宫格面试题
  14. react中使用构建缓存_如何使用React,GraphQL和Okta构建健康跟踪应用
  15. 查看计算机bios版本,如何查看电脑BIOS版本
  16. Acwing-4645. 选数异或
  17. Greenplum助医疗大数据从“奢侈品”走向常态化
  18. unreal 用于三维展示的改造 建筑 模型展示
  19. JS中字符串的创建、操作及其方法
  20. 缩放图像、切割图像、图像类型转换、彩色转黑白、文字水印、图片水印

热门文章

  1. Linux查看网卡带宽
  2. springboot 启动加载数据 commandLineRunner
  3. 漫谈Servlet(一)
  4. python名人名言代码打印_php随机输出名人名言的代码
  5. ASP.NET Core 基于SignalR实时通讯的前后端分离技术
  6. 在redis取数据若存在直接取,不存在在db中取,并放到缓存中
  7. java long常量池_Java提高篇之常量池
  8. bug记录:虚拟机ping不通外网
  9. 在windows下安装配置Ulipad
  10. 学习jQuery formValidator