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

目录
相关文章
|
6月前
|
供应链 Go C语言
掌握Go语言:探索Go语言基础,字符串连接、关键字、空格、格式化字符串的重要性(7)
掌握Go语言:探索Go语言基础,字符串连接、关键字、空格、格式化字符串的重要性(7)
|
3月前
|
JSON 人工智能 编译器
Go json 能否解码到一个 interface 类型的值
Go json 能否解码到一个 interface 类型的值
30 1
|
3月前
|
JSON Go 数据格式
Go - json.Unmarshal 遇到的小坑
Go - json.Unmarshal 遇到的小坑
59 9
|
3月前
|
JSON Go 数据格式
Go实现json字符串与各类struct相互转换
文章通过Go语言示例代码详细演示了如何实现JSON字符串与各类struct之间的相互转换,包括结构体对象生成JSON字符串和JSON字符串映射到struct对象的过程。
31 0
|
4月前
|
JSON Java Serverless
函数计算产品使用问题之如何使用Go SDK从HTTP上下文中提取JSON数据
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
安全 Go
Go语言的iota关键字有什么用途?
**Go语言中的`iota`是常量生成器,用于在`const`声明中创建递增的常量。`iota`在每个新的`const`块重置为0,然后逐行递增,简化了枚举类型或常量序列的定义。例如,定义星期枚举:** ```markdown ```go type Weekday int const ( Sunday Weekday = iota // 0 Monday // 1 Tuesday // 2 ... ) ``` 同样,`iota`可用于定义不同组的常量,如状态码和标志位,保持各自组内的递增,提高代码可读性。
|
4月前
|
JSON 前端开发 JavaScript
Go怎么解析不定JSON数据?
在Go中处理不确定结构的JSON数据,可以使用`map[string]interface{}`来解析,它能适应各种JSON键值对,但需要类型检查。另一种方法是使用`json.RawMessage`保存原始JSON,之后按需解析。此外,`json.Number`用于处理任意精度的数字。当JSON字段类型未知时,可以先解码到`interface{}`并做类型断言。第三方库如gjson和jsonparser提供更灵活的解析选项。
|
4月前
|
安全 Go
Go语言的iota关键字有什么用途?
在Go语言中, `iota` 是一个特殊常量生成器, 用于在 `const` 声明中创建递增的常量值。每当遇到新的 `const` 关键字时, `iota` 会重置为0并在每个常量声明行上递增1。这非常适合定义枚举类型或一组相关常量。`iota` 大大简化了枚举类型的定义过程, 并提供了类型安全的方法来表示固定值集合, 对于错误码、状态码等非常有用。
|
6月前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
172 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
5月前
|
JSON Go 数据格式
go之json使用
go之json使用
下一篇
无影云桌面