Go json omitempty关键字

简介: Go json omitempty关键字

omitempty的使用


将结构体转成json作为参数,请求某个服务。希望结构体某字段为空时,解析成的json没有该字段。 这就是omitempty关键字的作用,即忽略空值

如:

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID     int64  `json:"id"`
  Name   string `json:"string"`
  Gender string `json:"gender,omitempty"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "男",
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

执行结果为:

json of s =  {"id":15,"string":"XiaoMing","gender":"男"}

如果gender字段为空,即

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID     int64  `json:"id"`
  Name   string `json:"string"`
  Gender string `json:"gender,omitempty"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

则执行结果为:

json of s =  {"id":15,"string":"XiaoMing"}

而如果去掉omitempty标签,则执行结果为

json of s =  {"id":15,"string":"XiaoMing","gender":""}


omitempty的陷阱


不过该关键字有几个注意事项,或称之为"小坑"

如再增加一个address字段,为一个结构体

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID      int64   `json:"id"`
  Name    string  `json:"string"`
  Gender  string  `json:"gender,omitempty"`
  Address address `json:"address,omitempty"`
}
type address struct {
  Country  string `json:"country"`
  Province string `json:"province"`
  City     string `json:"accessKey"`
  Street   string `json:"street"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
    address{},
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

执行结果为:

json of s =  {"id":15,"string":"XiaoMing","address":{"country":"","province":"","accessKey":"","street":""}}

为什么明明Address字段加了omitempty,当其为空值时,json.Marshal时还是有这个字段?

这是因为,omitempty关键字无法忽略掉嵌套结构体


那该如何解决?

可以把Address字段定义为指针类型,这样 Golang 就能知道一个指针的“空值”是多少了,否则面对一个我们自定义的结构, Golang 是猜不出我们想要的空值的...

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID      int64    `json:"id"`
  Name    string   `json:"string"`
  Gender  string   `json:"gender,omitempty"`
  Address *address `json:"address,omitempty"`
}
type address struct {
  Country  string `json:"country"`
  Province string `json:"province"`
  City     string `json:"accessKey"`
  Street   string `json:"street"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
    nil,
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

输出为

json of s = {"id":15,"string":"XiaoMing"}


但如果是

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID      int64    `json:"id"`
  Name    string   `json:"string"`
  Gender  string   `json:"gender,omitempty"`
  Address *address `json:"address,omitempty"`
}
type address struct {
  Country  string `json:"country"`
  Province string `json:"province"`
  City     string `json:"accessKey"`
  Street   string `json:"street"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
    &address{},
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

则输出还是

json of s =  {"id":15,"string":"XiaoMing","address":{"country":"","province":"","accessKey":"","street":""}}

另一个陷阱,是对于用 omitempty 定义的 field ,如果给它赋的值恰好等于默认空值的话,在转为 json 之后也不会输出这个 field


参考

Golang 的 “omitempty” 关键字略解


omitempty源码


其源码位于src/encoding/asn1/common.go

// Given a tag string with the format specified in the package comment,
// parseFieldParameters will parse it into a fieldParameters structure,
// ignoring unknown parts of the string.
func parseFieldParameters(str string) (ret fieldParameters) {
  var part string
  for len(str) > 0 {
    // This loop uses IndexByte and explicit slicing
    // instead of strings.Split(str, ",") to reduce allocations.
    i := strings.IndexByte(str, ',')
    if i < 0 {
      part, str = str, ""
    } else {
      part, str = str[:i], str[i+1:]
    }
    switch {
    case part == "optional":
      ret.optional = true
    case part == "explicit":
      ret.explicit = true
      if ret.tag == nil {
        ret.tag = new(int)
      }
    case part == "generalized":
      ret.timeType = TagGeneralizedTime
    case part == "utc":
      ret.timeType = TagUTCTime
    case part == "ia5":
      ret.stringType = TagIA5String
    case part == "printable":
      ret.stringType = TagPrintableString
    case part == "numeric":
      ret.stringType = TagNumericString
    case part == "utf8":
      ret.stringType = TagUTF8String
    case strings.HasPrefix(part, "default:"):
      i, err := strconv.ParseInt(part[8:], 10, 64)
      if err == nil {
        ret.defaultValue = new(int64)
        *ret.defaultValue = i
      }
    case strings.HasPrefix(part, "tag:"):
      i, err := strconv.Atoi(part[4:])
      if err == nil {
        ret.tag = new(int)
        *ret.tag = i
      }
    case part == "set":
      ret.set = true
    case part == "application":
      ret.application = true
      if ret.tag == nil {
        ret.tag = new(int)
      }
    case part == "private":
      ret.private = true
      if ret.tag == nil {
        ret.tag = new(int)
      }
    case part == "omitempty":
      ret.omitEmpty = true
    }
  }
  return
}

json.Rawmessage,也许是这种场景更好的方案


另外,这种场景其实可以用json.Rawmessage

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID     int64  `json:"id"`
  Name   string `json:"string"`
  Gender string `json:"gender,omitempty"`
  //Address *address `json:"address,omitempty"`
  Address json.RawMessage `json:"address,omitempty"`
}
type address struct {
  Country  string `json:"country"`
  Province string `json:"province"`
  City     string `json:"accessKey"`
  Street   string `json:"street"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
    nil,
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

输出为:

json of s = {"id":15,"string":"XiaoMing"}


interface{}也可以

package main
import (
  "encoding/json"
  "fmt"
)
type User struct {
  ID     int64  `json:"id"`
  Name   string `json:"string"`
  Gender string `json:"gender,omitempty"`
  //Address *address `json:"address,omitempty"`
  //Address json.RawMessage `json:"address,omitempty"`
  Address interface{} `json:"address,omitempty"`
}
type address struct {
  Country  string `json:"country"`
  Province string `json:"province"`
  City     string `json:"accessKey"`
  Street   string `json:"street"`
}
func main() {
  s := User{
    15,
    "XiaoMing",
    "",
    nil,
  }
  sJson, err := json.Marshal(s)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("json of s = ", string(sJson))
}

输出为:

json of s = {"id":15,"string":"XiaoMing"}

目录
相关文章
|
4天前
|
供应链 Go C语言
掌握Go语言:探索Go语言基础,字符串连接、关键字、空格、格式化字符串的重要性(7)
掌握Go语言:探索Go语言基础,字符串连接、关键字、空格、格式化字符串的重要性(7)
|
4天前
|
JSON 编解码 Go
【Go语言专栏】Go语言中的JSON编码与解码
【4月更文挑战第30天】Go语言内置JSON编码解码支持,简化了数据交换。`json.Marshal`用于将Go结构体转换为JSON,如示例中`Person`结构体的编码。`json.Unmarshal`则将JSON数据反序列化到结构体,需传入结构体变量的地址。错误处理至关重要,特别是在处理大量数据时,要注意性能优化,如避免不必要的转换和重复操作。了解自定义编码解码和最佳实践能提升开发效率。掌握这些技能,有助于构建高效Go应用。
|
4天前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
23 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
4天前
|
编译器 Go 开发者
Go语言入门|包、关键字和标识符
Go语言入门|包、关键字和标识符
34 0
|
4天前
|
Go
Go 语言学习:了解 const 关键字及常量声明
如果一个变量应该有一个固定的、不能改变的值,你可以使用const关键字。 const关键字将变量声明为"常量",这意味着它是不可改变和只读的。
46 0
|
5月前
|
JSON Go 数据格式
go 变量与json相互转换
go 变量与json相互转换
43 1
|
6月前
|
JSON Linux 测试技术
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
|
7月前
|
存储 XML JSON
互联网协议必备:Go语言中JSON的序列化与反序列化
互联网协议必备:Go语言中JSON的序列化与反序列化
79 0
|
7月前
|
Go 开发者
终于全面掌握Go语言关键字和标识符用法 新手进阶必备 原创 Go先锋
终于全面掌握Go语言关键字和标识符用法 新手进阶必备 原创 Go先锋
33 0
终于全面掌握Go语言关键字和标识符用法 新手进阶必备 原创 Go先锋
|
7月前
|
Go
Go语言type关键字终于被玩明白了 类型别名的秘密都在这里
Go语言type关键字终于被玩明白了 类型别名的秘密都在这里
49 0