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(mapKV, 0) {} {} OMIT
Array: 0T fields zero 0T \[\] OMIT OMIT
Array: NT 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 ❌ ❌ ❌

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

相关推荐
每天进步一点点km5 小时前
自用-牛客网-华为机试编程模拟题1-python
华为od·华为·面试
frjc10 小时前
分布式服务拆分实战指南:从底层逻辑到面试话术
微服务·面试·职场和发展
考研保研资料分享10 小时前
2025生科保研北大直博:英语摘要、科研PPT与赶场复盘
面试
香蕉大香蕉(06敬畏市场)11 小时前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
ShineWinsu11 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
师夷长技以自愈11 小时前
第 3 讲:多 Agent——Supervisor 分诊 + 专职 Worker
面试
怕浪猫12 小时前
我有个朋友,工作八年,公司从 300 人减到 80 人
面试·程序员
考研保研资料分享12 小时前
2024财会跨保北大金融科技:三场笔面试与经管法混申复盘
科技·面试·金融
hourinX12 小时前
从 v1 到 v2,我重新拆了头像生成的整条链路—— gdenticon 重构日志(二)
go
NiceZack12 小时前
Hadoop 部署全流程教程:从新装 CentOS 到伪分布式与完全分布式
hadoop·分布式·centos