Go中的“omitempty” | 青训营

156 阅读2分钟

在完成大项目的过程中,避免不了会在json和struct之间频繁转换,这里感谢网上的各种转换工具,省去了繁琐的构造结构体的过程。为了将代码中的结构体与json数据解耦,通常我们会在结构体的field类型后加上解释说明。例如:

{
    "status_code": 0,
    "status_msg": "string",
    "user_id": 0,
    "token": "string"
}

对应的结构体可以为

type Response struct {
    StatusCode int `json:"status_code"`
    StatusMsg string `json:"status_msg"`
    UserID int `json:"user_id"`
    Token string `json:"token"`
}

在编写业务逻辑的过程中,会发现有时候并不需要传递结构体中的某些字段,但是返回的json数据中该字段依然存在,这时候我们就需要使用omitempty关键字,这里我们不想UserIDToken字段存在默认值,可以这样定义结构体

type Response struct {
    StatusCode int `json:"status_code"`
    StatusMsg string `json:"status_msg"`
    UserID int `json:"user_id,omitempty"`
    Token string `json:"token,omitempty"`
}

omitempty使用存在的问题

嵌套结构体

假定有如下结构体

type User struct {
    UserID int `json:"user_id"`
}

type Response struct {
    StatusCode int `json:"status_code"`
    User User `json:"user,omitempty"`
}

在使用Response时我们想主动忽略其中的User字段,但是运行会发现这样是行不通的,User字段无论如何都不会被忽略。

正确做法是将嵌套结构体定义为指针类型,当传入为nil时,不会为其分配默认值。

//正确定义方法
type Response struct {
    StatusCode int `json:"status_code"`
    User *User `json:"user,omitempty"`
}

字段默认值

还是回到最初的结构体

type Response struct {
    StatusCode int `json:"status_code"`
    StatusMsg string `json:"status_msg"`
    UserID int `json:"user_id,omitempty"`
    Token string `json:"token,omitempty"`
}

假如我们想定义一个UserID为0的结构体,将其转换为json数据会发现不存在user_id字段。这和我们刚刚为了解决嵌套结构体问题时的思路很像,指针的空值是nil,当对应字段值为nil时也不会被解析,所以可以总结一下,当使用omitempty关键字时,GoLang会忽略结构体中值为空或者为默认值的字段。

想要解决默认值问题,还是得采用指针的方法,因为指针的默认值nil一般不会采用,修改后的结构体如下

type Response struct {
    StatusCode int `json:"status_code"`
    StatusMsg string `json:"status_msg"`
    UserID *int `json:"user_id,omitempty"`
    Token string `json:"token,omitempty"`
}