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"}

目录
相关文章
|
1月前
|
Go 索引
go语言使用range关键字
go语言使用range关键字
34 7
|
2月前
|
安全 Go 索引
go语言使用 range 关键字
go语言使用 range 关键字
30 3
|
2月前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
35 3
|
2月前
|
JSON JavaScript 前端开发
Go语言中json序列化的一个小坑,建议多留意一下
在Go语言开发中,JSON因其简洁和广泛的兼容性而常用于数据交换,但其在处理数字类型时存在精度问题。本文探讨了JSON序列化的一些局限性,并介绍了两种替代方案:Go特有的gob二进制协议,以及msgpack,两者都能有效解决类型保持和性能优化的问题。
59 7
|
2月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
59 4
|
5月前
|
JSON 人工智能 编译器
Go json 能否解码到一个 interface 类型的值
Go json 能否解码到一个 interface 类型的值
45 1
|
5月前
|
存储 Go
掌握 Go 语言的 defer 关键字
掌握 Go 语言的 defer 关键字
|
5月前
|
JSON Go 数据格式
Go - json.Unmarshal 遇到的小坑
Go - json.Unmarshal 遇到的小坑
84 9
|
5月前
|
JSON Go 数据格式
Go实现json字符串与各类struct相互转换
文章通过Go语言示例代码详细演示了如何实现JSON字符串与各类struct之间的相互转换,包括结构体对象生成JSON字符串和JSON字符串映射到struct对象的过程。
44 0
|
6月前
|
安全 Go
Go语言的iota关键字有什么用途?
**Go语言中的`iota`是常量生成器,用于在`const`声明中创建递增的常量。`iota`在每个新的`const`块重置为0,然后逐行递增,简化了枚举类型或常量序列的定义。例如,定义星期枚举:** ```markdown ```go type Weekday int const ( Sunday Weekday = iota // 0 Monday // 1 Tuesday // 2 ... ) ``` 同样,`iota`可用于定义不同组的常量,如状态码和标志位,保持各自组内的递增,提高代码可读性。

热门文章

最新文章

下一篇
开通oss服务