内置类型的零值/默认值
变量声明但未显式初始化时,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 | ❌ | ❌ | ❌ |
✨ 微信公众号【凉凉的知识库】同步更新,欢迎关注获取最新最有用的知识 ✨