【问题标题】:golang json marshal: how to omit empty nested structgolang json marshal:如何省略空嵌套结构
【发布时间】:2015-10-31 02:03:45
【问题描述】:

go playground

如上面的代码所示,可以使用json:",omitempty" 省略结构中的某些字段以出现在json 中。

例如

type ColorGroup struct {
    ID     int `json:",omitempty"`
    Name   string
    Colors []string
}
type Total struct {
    A ColorGroup`json:",omitempty"`
    B string`json:",omitempty"`
}
group := Total{
       A: ColorGroup{},

}

在这种情况下,B 不会出现在 json.Marshal(group)

但是,如果

group := Total{
       B:"abc",

}

A 仍会出现在 json.Marshal(group)

{"A":{"Name":"","Colors":null},"B":"abc"}

问题是我们如何得到唯一的

{"B":"abc"}

编辑: 经过一番谷歌搜索,这里有一个建议use pointer,换句话说,把Total变成

type Total struct {
    A *ColorGroup`json:",omitempty"`
    B string`json:",omitempty"`
}

【问题讨论】:

  • 如果这对某些人不起作用,结构标记中省略前的逗号很重要。当我忽略它时,该字段总是被忽略,即使它不是空的。
  • 以防万一有人遇到我的问题...不要在逗号和省略号之间放置空格。
  • 也许这个答案会有所帮助? stackoverflow.com/a/18088527/2271198

标签: json go


【解决方案1】:

来自the documentation

结构值编码为 JSON 对象。每个导出的结构字段都成为对象的成员,除非

  • 字段的标签是“-”,或者
  • 该字段为空,其标签指定“omitempty”选项。

空值是 false、0、任何 nil 指针或接口值,以及任何长度为零的数组、切片、映射或字符串。

group 的声明中,暗示group.A 将是ColorGroup 结构类型的零值。请注意,结构类型的零值在被视为“空值”的事物列表中未提及。

如您所见,针对您的情况的解决方法是使用指针。如果您没有在 group 的声明中指定 A,这将起作用。如果你指定它是一个指向零结构的指针,那么它会再次出现。

playground link:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {
    type colorGroup struct {
        ID     int `json:",omitempty"`
        Name   string
        Colors []string
    }
    type total struct {
        A *colorGroup `json:",omitempty"`
        B string     `json:",omitempty"`
    }

    groupWithNilA := total{
        B: "abc",
    }
    b, err := json.Marshal(groupWithNilA)
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stderr.Write(b)

    println()

    groupWithPointerToZeroA := total{
        A: &colorGroup{},
        B: "abc",
    }
    b, err = json.Marshal(groupWithPointerToZeroA)
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stderr.Write(b)
}

【讨论】:

  • 我知道这是一篇旧帖子。但我有一个问题。如果使用指针是一种解决方法,那么问题是什么?
  • 为什么不总是对结构体字段类型使用指针?
【解决方案2】:

这是一种替代解决方案,以防您想避免使用指向结构的指针。 Container 结构体实现了 json.Marshaller,它允许我们决定应该省略 strcut 的哪些成员。

https://play.golang.com/p/hMJbQ-QQ5PU

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    for _, c := range []Container{
        {},
        {
            Element: KeyValue{
                Key:   "foo",
                Value: "bar",
            },
        },
    } {
        b, err := json.Marshal(c)
        if err != nil {
            panic(err)
        }
        fmt.Println(string(b))
    }
}

type Container struct {
    Element KeyValue
}

func (c Container) MarshalJSON() ([]byte, error) {
    // Alias is an alias type of Container to avoid recursion.
    type Alias Container

    // AliasWithInterface wraps Alias and overrides the struct members,
    // which we want to omit if they are the zero value of the type.
    type AliasWithInterface struct {
        Alias
        Element interface{} `json:",omitempty"`
    }

    return json.Marshal(AliasWithInterface{
        Alias:   Alias(c),
        Element: c.Element.jsonValue(),
    })
}

type KeyValue struct {
    Key   string
    Value string
}

// jsonValue returns nil if kv is the zero value of KeyValue. It returns kv otherwise.
func (kv KeyValue) jsonValue() interface{} {
    var zero KeyValue
    if kv == zero {
        return nil
    }
    return kv
}

编辑:添加文档

【讨论】:

    【解决方案3】:

    简单的方法

    type <name> struct {
    < varname > < vartype > \`json : -\`
    }
    

    示例:

    type Boy struct {
    name string \`json : -\`
    }
    

    这样编组name 不会被序列化。

    【讨论】:

    • 至少有 15 人对此​​投了反对票,但没有向我们解释原因
    • @JeshanBabooa, 1. name 字段未导出!导出字段的首字母必须大写。 2.json:"-"在字段导出时生效。 3. 最后一句话:如果该字段被导出json:"-" 将完全省略它......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多