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

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

相关推荐
哈里谢顿1 天前
agnes0317面试总结
面试
哈里谢顿1 天前
golang常见面试题总结
面试·go
江不清丶1 天前
Kafka消息幂等性深度解析:从重复消费到Exactly-Once的终极方案
分布式·kafka
AI淇橦学1 天前
零基础学 Agent :拆解一个 Agent 的「零件清单」——8 个模块逐一讲透 第 2 期
面试
Lee川1 天前
时空迷宫探险记:从O(1)到O(2^n)的算法进化论
算法·面试
前端Hardy1 天前
别再手动调 Prompt 了!这款开源神器让 AI 输出质量提升 300%,支持 Claude、GPT、Gemini,还免费开源!
前端·javascript·面试
yuhaiqiang1 天前
谈谈什么是多AI交叉论证思维
前端·后端·面试
加洛斯1 天前
JAVA知识梳理:一文搞懂集合中的List与ArrayList的基础与进阶
java·后端·面试
发现一只大呆瓜1 天前
深度拆解 fetch-event-source库实现原理
前端·javascript·面试
前端Hardy1 天前
为什么资深前端都在悄悄学 WebAssembly?
前端·javascript·面试