Daily Study
更新: 8/7/2025 字数: 0 字 时长: 0 分钟
Daily Plan
#todo
- [ ]
trpc-go 中的 omitempty
trpc-go
中的 omitempty
行为是直接继承并利用了 Go 语言本身 encoding/json
包中的 omitempty
标签特性。
在 Go 语言中,当你定义一个结构体 (struct) 时,可以为字段添加 "标签" (tags)。这些标签可以为各种库(如 JSON、XML、ORM 库等)提供元数据,指导它们如何处理这个字段,对于encoding/json
包,omitempty
是一个非常常用的标签选项。它的含义是:“如果在对这个结构体实例进行 JSON 序列化(编码)时,该字段的值为其类型的零值 (zero value),那么在最终生成的 JSON 字符串中,就完全忽略这个字段。”
Go 语言中各种类型的零值
类型 | 零值 |
---|---|
int , int8 , int32 , int64 | 0 |
uint , uintptr 等 | 0 |
float32 , float64 | 0.0 |
bool | false |
string | "" (空字符串) |
pointer (*T) | nil |
interface | nil |
slice | nil |
map | nil |
channel , function | nil |
struct | 所有字段都为其零值的实例 |
omitempty
使得生成的 JSON 输出更加简洁,只包含那些被显式赋值(非零值)的字段。
omitempty
在 trpc-go
中的应用场景和作用
在 trpc-go
的上下文中,结构体通常被用作 API 的输入(请求体)和输出(响应体)。omitempty
的作用主要体现在 客户端与服务端的数据交互 过程中。
主要作用:
减少网络传输量:这是最直接的好处。对于可选的请求参数或响应字段,如果客户端没有提供或者服务端没有生成,那么这些字段就不会被序列化到 JSON 中,从而减小了请求或响应体的大小,节省了网络带宽。
明确区分“未提供”与“提供了零值”:这一点非常重要,尤其是在
UPDATE
或PATCH
类的操作中。不使用
omitempty
:如果你想更新一个用户的年龄为0
,你传递{"age": 0}
。服务端收到后,会将用户的年龄更新为0
。使用
omitempty
:如果你传递{"age": 0}
,由于0
是int
的零值,这个字段在序列化时会被忽略掉,最终发送的 JSON 可能是{"user_name": "some_name"}
。服务端在反序列化时,Age
字段将保持为 Go 结构体中的零值0
。这看起来没有区别。
针对指针类型,例如你想实现一个部分更新的功能,有如下结构体,定义了三个字段:
// 服务端的输入结构体
type UpdateUserRequest struct {
UserName *string `json:"user_name,omitempty"`
Age *int `json:"age,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
}
在这个设计中:
想更新
age
为30
:客户端发送{"age": 30}
。服务端收到的UpdateUserRequest
结构体中,Age
字段是一个指向30
的指针(非nil
)。想更新
age
为0
:客户端发送{"age": 0}
。服务端收到的UpdateUserRequest
结构体中,Age
字段是一个指向0
的指针(非nil
)。不想更新
age
字段:客户端不发送age
字段,即发送{"user_name": "new_name"}
。由于omitempty
的作用,服务端收到的UpdateUserRequest
结构体中,Age
字段的值是nil
。
在服务端的逻辑中:
// user, _ := GetUserFromDB()
// req := ctx.Request() // 获取请求体
if req.UserName != nil {
user.UserName = *req.UserName
}
if req.Age != nil {
user.Age = *req.Age
}
if req.IsActive != nil {
user.IsActive = *req.IsActive
}
// SaveUserToDB(user)
通过判断指针是否为 nil
,我们可以精确地知道客户端到底想更新哪些字段,即使目标值是 false
或 0
这种零值。如果没有 omitempty
和指针的配合,我们就无法区分“客户端希望把值设为 false
”和“客户端根本没传这个字段”。
总结
在 trpc-go
(以及任何使用 Go encoding/json
的框架)中,omitempty
是一个用于控制 JSON 序列化的强大工具。
何时使用:
当你的 API 输入或输出中有可选字段时。
在实现**部分更新(PATCH)**逻辑时,强烈推荐将字段定义为指针类型,并配合
omitempty
使用。当你希望 API 响应更简洁,不返回没有意义的零值字段时。
如何工作:
- 在序列化(Go struct -> JSON)时,如果字段的值是其类型的零值,则该字段会被完全忽略。
注意事项:
要小心基本类型(
int
,bool
)的零值。如果你需要明确区分“传递了false
”和“未传递”,请使用指针类型*bool
。omitempty
只在序列化(编码)时起作用,在反序列化(JSON -> Go struct)时,如果 JSON 中没有某个字段,那么结构体中对应的字段就会被赋值为其零值,omitempty
标签对此没有影响。