Go中的零值与空值,你搞懂了么?

内置类型的零值/默认值

变量声明但未显式初始化时,Go 自动赋的默认值。它保证"未初始化"也有确定、可用的值

TYPE ZERO VALUE
Integer 0
Floating point 0.0
Boolean false
String ""
Pointer nil
Interface nil
Slice nil
Map nil
Array fields zero (每个元素都是其零值)
Struct fields zero (每个元素都是其零值)
Channel nil
Function nil

Json序列化中的omitempty&omitzero

omitempty

当对一个结构体的某个字段的tag设置为omitempty时,如果这个字段是空值(empty value,和零值不一样)时,那么这个字段就会在序列化时省略

The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.

omitempty标签的判断逻辑如下:

  • 对于布尔类型:false被视为空
  • 对于数值类型:0被视为空
  • 对于指针、接口:nil被视为空
  • 对于字符串:""(空字符串)被视为空
  • 对于数组、切片、map:长度为0被视为空,既包含未初始化的又包含空的

对于空结构体、所有字段都为默认值的零值结构体、以及一些实际含义为零的结构体(例如time.Time{}),omitempty都无能为力,会进行输出。

因此在Go 1.24之前想对某个结构体不输出,可选的一种方案是使用指针类型

go 复制代码
type VanillaStruct struct {
    StructTyp1 struct{}        // 空结构体
    StructTyp2 struct{ A int } // 零值结构体
    TimeTyp    time.Time       // 实际含义为零的结构体
​
    StructTyp3 *struct{}
    StructTyp4 *struct{ A int }
    TimeTyp2   *time.Time
}
​
type OmitemptyStruct struct {
    StructTyp1 struct{}        `json:",omitempty"`
    StructTyp2 struct{ A int } `json:",omitempty"`
    TimeTyp1   time.Time       `json:",omitempty"`
​
    StructTyp3 *struct{}        `json:",omitempty"`
    StructTyp4 *struct{ A int } `json:",omitempty"`
    TimeTyp2   *time.Time       `json:",omitempty"`
}
​
func main() {
    s1 := VanillaStruct{}
    ss1, err := json.Marshal(s1)
    fmt.Println(err, string(ss1)) 
    // {"StructTyp1":{},"StructTyp2":{"A":0},"TimeTyp":"0001-01-01T00:00:00Z","StructTyp3":null,"StructTyp4":null,"TimeTyp2":null}
​
    s2 := OmitemptyStruct{}
    ss2, err := json.Marshal(s2)
    fmt.Println(err, string(ss2)) 
    // {"StructTyp1":{},"StructTyp2":{"A":0},"TimeTyp1":"0001-01-01T00:00:00Z"}
}

omitzero

Go 1.24 给 encoding/json 新增omitzero:按零值(zero value)省略

在序列化时,omitzero选项指定如果字段值为零,则该结构体字段应被省略

  • 如果该类型定义了IsZero() bool方法,那么这个零值就通过IsZero方法来判断
  • 否则是根据字段是否是零值(通过reflect.Value.IsZero判断)来判断
go 复制代码
type VanillaStruct struct {
    StructTyp1 struct{}        // 空结构体
    StructTyp2 struct{ A int } // 零值结构体
    TimeTyp    time.Time       // 实际含义为零的结构体
}
​
type OmitzeroStruct struct {
    StructTyp1 struct{}        `json:",omitzero"`
    StructTyp2 struct{ A int } `json:",omitzero"`
    TimeTyp1   time.Time       `json:",omitzero"`
}
​
func main() {
    s1 := VanillaStruct{}
    ss1, err := json.Marshal(s1)
    fmt.Println(err, string(ss1))
    // {"StructTyp1":{},"StructTyp2":{"A":0},"TimeTyp":"0001-01-01T00:00:00Z"}
​
    s2 := OmitzeroStruct{}
    ss2, err := json.Marshal(s2)
    fmt.Println(err, string(ss2))
    // {}
}

总结

下面是一个完整的Go示例,展示了omitempty&omitzero标签在不同类型上的应用:

TYPE ZERO VALUE EMPTY VALUE WITHOUT OMIT OMITEZERO OMITEMPTY
Integer 0 0 0 OMIT OMIT
Floating point 0 0 0 OMIT OMIT
Boolean FALSE FALSE FALSE OMIT OMIT
String "" "" "" OMIT OMIT
Pointer nil nil null OMIT OMIT
Interface nil nil null OMIT OMIT
Slice nil nil null OMIT OMIT
Slice nil make([]T, 0) [] [] OMIT
Map nil nil null OMIT OMIT
Map nil make(map[K]V, 0) {} {} OMIT
Array: [0]T fields zero [0]T [] OMIT OMIT
Array: [N]T fields zero [T] OMIT [T]
Struct: struct{} fields zero {} OMIT {}
Struct: struct{ F T } fields zero {"F": T} OMIT {"F": T}
Channel nil nil
Function nil nil

✨ 微信公众号【凉凉的知识库】同步更新,欢迎关注获取最新最有用的知识 ✨

相关推荐
2501_9333295516 小时前
技术架构深度解析:Infoseek舆情监测系统的全链路设计与GEO时代的技术实践
开发语言·人工智能·分布式·架构
前端大波16 小时前
前端面试通关包(2026版,完整版)
前端·面试·职场和发展
鬼先生_sir16 小时前
Zookeeper:从入门到精通
分布式·zookeeper·云原生
walking95718 小时前
Vue3 日历组件选型指南:五大主流方案深度解析
前端·vue.js·面试
huohuopro20 小时前
Hbase伪分布式远程访问配置
数据库·分布式·hbase
MgArcher21 小时前
Python高级特性:高阶函数完全指南
后端·面试
何陋轩21 小时前
Redis深度解析:把缓存核心讲透,吊打面试官
redis·面试
深蓝轨迹21 小时前
面试常见的jdk---LTS版本新特性梳理
java·面试·jdk
Francek Chen1 天前
【大数据存储与管理】NoSQL数据库:01 NoSQL简介
大数据·数据库·分布式·nosql
sbjdhjd1 天前
Docker | 核心概念科普 + 保姆级部署
linux·运维·服务器·docker·云原生·面试·eureka