Skip to content

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, int640
uint, uintptr0
float32, float640.0
boolfalse
string"" (空字符串)
pointer (*T)nil
interfacenil
slicenil
mapnil
channel, functionnil
struct所有字段都为其零值的实例

omitempty 使得生成的 JSON 输出更加简洁,只包含那些被显式赋值(非零值)的字段。

omitemptytrpc-go 中的应用场景和作用

trpc-go 的上下文中,结构体通常被用作 API 的输入(请求体)和输出(响应体)。omitempty 的作用主要体现在 客户端与服务端的数据交互 过程中。

主要作用:

  1. 减少网络传输量:这是最直接的好处。对于可选的请求参数或响应字段,如果客户端没有提供或者服务端没有生成,那么这些字段就不会被序列化到 JSON 中,从而减小了请求或响应体的大小,节省了网络带宽。

  2. 明确区分“未提供”与“提供了零值”:这一点非常重要,尤其是在 UPDATEPATCH 类的操作中。

    • 不使用 omitempty:如果你想更新一个用户的年龄为 0,你传递 {"age": 0}。服务端收到后,会将用户的年龄更新为 0

    • 使用 omitempty:如果你传递 {"age": 0},由于 0int 的零值,这个字段在序列化时会被忽略掉,最终发送的 JSON 可能是 {"user_name": "some_name"}。服务端在反序列化时,Age 字段将保持为 Go 结构体中的零值 0。这看起来没有区别。

  3. 针对指针类型,例如你想实现一个部分更新的功能,有如下结构体,定义了三个字段:

go
// 服务端的输入结构体
type UpdateUserRequest struct {
    UserName *string `json:"user_name,omitempty"`
    Age      *int    `json:"age,omitempty"`
    IsActive *bool   `json:"is_active,omitempty"`
}

在这个设计中:

  • 想更新 age30:客户端发送 {"age": 30}。服务端收到的 UpdateUserRequest 结构体中,Age 字段是一个指向 30 的指针(非 nil)。

  • 想更新 age0:客户端发送 {"age": 0}。服务端收到的 UpdateUserRequest 结构体中,Age 字段是一个指向 0 的指针(非 nil)。

  • 不想更新 age 字段:客户端不发送 age 字段,即发送 {"user_name": "new_name"}。由于 omitempty 的作用,服务端收到的 UpdateUserRequest 结构体中,Age 字段的值是 nil

在服务端的逻辑中:

go
// 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,我们可以精确地知道客户端到底想更新哪些字段,即使目标值是 false0 这种零值。如果没有 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 标签对此没有影响。

菜就多练

本站访客数 人次 本站总访问量