golang omitempty 总结

在使用Golang的时候,不免会使用Json和结构体的相互转换,这时候常用的就是 json.Marshaljson.Unmarshal两个函数。

这时候在定义json结构体的时候,我们会用到omitempty这个字段,这个字段看似简单,但是却有很多小坑,这篇文章带你稍微研究一下他的用途和功能

Basic Usage

当我们设置json的struct的时候,会定义每个字段对一个json的格式,比如定义一个dog 结构体:

type Dog struct {
Breed string
WeightKg int
}

现在我们对他进行初始化,将其编码为JSON格式:

func main() {
d := Dog{
Breed: "dalmation",
WeightKg: 45,
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

则输出的结果为:{"Breed":"dalmation","WeightKg":45},你可点击这里.

现在假如有一个结构体变量我们没初始化,那么结果可能也会跟我们预期的不太一样:

func main() {
d := Dog{
Breed: "pug",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出的结果为:{"Breed":"pug","WeightKg":0},明显dog的weight是未知,而不是0,并不是我们想要的结果,我们更想要的结果是:"WeightKg":null

为了实现这样的目的,我们这时候应该使用omitempty 变量来帮我们实现,当我们在Dog结构体加上这个tag的时候:

type Dog struct {
Breed string
// The first comma below is to separate the name tag from the omitempty tag
WeightKg int `json:",omitempty"`
}

输出结果为:{"Breed":"pug"}。现在WeightKg就被设置为默认零值(对于int应该为0,对于string应该为"", 指针的话应该为nil)。

不能单纯使用omitted

当结构体相互嵌套的时候,那么omitempty就可能出现问题,比如:

type dimension struct {
Height int
Width int
} type Dog struct {
Breed string
WeightKg int
Size dimension `json:",omitempty"`
} func main() {
d := Dog{
Breed: "pug",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出结果为:

{"Breed":"pug","WeightKg":0,"Size":{"Height":0,"Width":0}}

我们已经使用omitempty标注的dimension还是显示了出来。这是因为结构体dimension不知道空值是什么,GO只知道简单结构体例如int,string,pointer 这种类型的空值,为了不显示我们没有提供值的自定义结构体,我们可以使用结构体指针:

type Dog struct {
Breed string
WeightKg int
// Now `Size` is a pointer to a `dimension` instance
Size *dimension `json:",omitempty"`
}

运行结果为:

{"Breed":"pug","WeightKg":0}

为什么会这样呢?因为指针是基本类型啊,Golang知道他的空值是啥,所以就直接赋值为nil(指针类型的空值)。

现在出一个问题,下面的程序的初始结果是什么?

type Dog struct {
Age *int `json:",omitempty"`
} func main() {
age := 0
d := Dog{
Age: &age,
} b, _ := json.Marshal(d)
fmt.Println(string(b))
}
  • A. {"Age":0}
  • B. {}

答案在最后揭晓。

0, "", nil 三者的区别

现在很难的很区别的是:零值,值为0,默认值。

比如我们设置一个restaurant结构体:

type Restaurant struct {
NumberOfCustomers int `json:",omitempty"`
} func main() {
d := Restaurant{
NumberOfCustomers: 0,
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

他的输出结果为:

{}

这肯定不是我们想要的结果,因为这个时候我们想要他输出0,他却没有任何值输出。因为Golang把0当成了零值,所以跟没有赋值是一样的,比如:

type Restaurant struct {
NumberOfCustomers int `json:",omitempty"`
Name string
} func main() {
d := Restaurant{
//给NumberOfCustomers赋值
NumberOfCustomers: 0,
Name: "hello",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

type Restaurant struct {
NumberOfCustomers int `json:",omitempty"`
Name string
} func main() {
d := Restaurant{
//未给NumberOfCustomers赋值
Name: "hello",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

二者结果都是:{"Name":"hello"}

解决这样的问题的一种方法是使用int指针,因为int指针的空值为nil,当我想输出0的时候,我传进去地址,地址肯定不是空值nil,这样肯定会显示出来0.

type Restaurant struct {
NumberOfCustomers *int `json:",omitempty"`
} func main() {
d1 := Restaurant{}
b, _ := json.Marshal(d1)
fmt.Println(string(b))
//Prints: {} n := 0
d2 := Restaurant{
NumberOfCustomers: &n,
}
b, _ = json.Marshal(d2)
fmt.Println(string(b))
//Prints: {"NumberOfCustomers":0}
}

基于上,我们应该谨慎使用omitempty,如果选择使用了他,那你就要第一时间知道,各个值的空值是什么?当我没有给某个变量赋值的时候,他应该是什么样的,我想要什么的输出?这都是你要仔细斟酌的。

好了,现在公布答案:A:因为他是int类型的指针,我们传进去的也是指针,所以不会有任何问题。同时&age不是指针的nil值,所以不会被忽略,显示的时候不会有问题,就是0.

ref: https://www.sohamkamani.com/golang/2018-07-19-golang-omitempty/; https://golang.org/pkg/encoding/json/

golang omitempty 总结的更多相关文章

  1. Golang omitempty 的用法

    原文链接:https://blog.csdn.net/skh2015java/article/details/90720692omitempty作用是在json数据结构转换时,当该字段的值为该字段类型 ...

  2. 【解决了一个小问题】golang protocol buffers 3中去掉json标签中的omitempty

    参考了这篇帖子:golang protobuf从生成的json标记中删除omitempty标记 由于是在windows上开发,因此写了一个python脚本来解决: remove_tag.py impo ...

  3. dynamodb golang query one Item

    golang  dynamodb  query  oneItem  and unmarshal  to object // +build example package main import ( / ...

  4. golang json string remove field

    golang中如何移除多余的field? 同样是json结构,不能像js 的json一样 delete key 直接移除,网上找了很多相似的,还没找到解决办法,先mark一下 感谢大神提供解决思路,设 ...

  5. golang mongodb (mgo)插入或读取文档的字段值为空(nil)问题解决

    问题描述 当使用mgo操作mongodb时,遇到数据插入正常,但是在数据库查看时只能看到objectid被插入了:读取的时候,可以查询到记录,但是读入对象时,却所有的值均为0或者空的情况. mongo ...

  6. golang 如何验证struct字段的数据格式

    本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/125 假设我们有如下结构体: type User struct ...

  7. Golang websocket推送

    Golang websocket推送 在工作用主要使用的是Java,也做过IM(后端用的netty websocket).最近想通过Golang重写下,于是通过websocket撸了一个聊天室. 项目 ...

  8. golang自定义struct字段标签

    原文链接: https://sosedoff.com/2016/07/16/golang-struct-tags.html struct是golang中最常使用的变量类型之一,几乎每个地方都有使用,从 ...

  9. golang json用法讲解

    简介 json格式可以算我们日常最常用的序列化格式之一了,Go语言作为一个由Google开发,号称互联网的C语言的语言,自然也对JSON格式支持很好.但是Go语言是个强类型语言,对格式要求极其严格而J ...

随机推荐

  1. 《GNU_makefile》第六章——变量

    makefile中的变量特征和C语言中的宏一样. 变量使用 =,:=,?= 和 define 定义 一些特殊的自动化变量:$< $@ $^ $* 1.变量的引用 通过 $(VAR) 或 ${VA ...

  2. (3)ElasticSearch在linux环境中安装与配置head插件

    1.简介 ElasticSearch-Head跟Kibana一样也是一个针对ElasticSearch集群操作的API的可视化管理工具,它提供了集群管理.数据可视化.增删改查.查询语句等功能,最重要还 ...

  3. Angular变更检测策略报错

    报错信息: ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was ...

  4. yum 常用命令使用

    1.向服务器上传文件或者下载文件 我们知道我们经常需要向服务器上传文件,或者从服务器下载文件,rz和sz命令可以满足我们的要求, 只不过默认情况下是不能使用的.我们需要使用yum install lr ...

  5. __all__有趣的属性

    python有趣的属性__all__可用于模块导入时限制,如:from module import *此时被导入模块若定义了__all__属性,则只有all内指定的属性.方法.类可被导入:若没定义,则 ...

  6. 大数据和Hadoop平台介绍

    大数据和Hadoop平台介绍 定义 大数据是指其大小和复杂性无法通过现有常用的工具软件,以合理的成本,在可接受的时限内对其进行捕获.管理和处理的数据集.这些困难包括数据的收入.存储.搜索.共享.分析和 ...

  7. kali 安装redis

    wget http://download.redis.io/releases/redis-2.8.3.tar.gz    下载 tar xzf redis-2.8.3.tar.gz          ...

  8. redhat-DHCP服务的配置与应用

    DHCP服务器为客户端提供自动分配IP地址的服务,减轻网管的负担 首先 rpm -q dhcp 查看是否安装dhcp yum -y install dhcp进行安装 安装完成 dhcp服务配置 dhc ...

  9. springboot实战开发全套教程,让开发像搭积木一样简单!Github星标已上10W+!

    前言 先说一下,这份教程在github上面星标已上10W,下面我会一一给大家举例出来全部内容,原链接后面我会发出来!首先我讲一下接下来我们会讲到的知识和技术,对比讲解了多种同类技术的使用手日区别,大家 ...

  10. 使用Camtasia创作抖音卡点视频

    空闲的时候刷一刷抖音相信已经成为很多人的日常啦,抖音里面的视频形式多种多样,而其中的卡点视频更是被大家热烈追捧.如果你外出旅行拍摄了很多好看的照片,就很适合用卡点视频的形式展现出来. 如果你想要制作这 ...