英文:
golang json marshal: how to omit empty nested struct
问题
如上所示的代码,可以使用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"}
编辑:
经过一些搜索,这里有一个建议使用指针,换句话说,将Total
改为:
type Total struct {
A *ColorGroup `json:",omitempty"`
B string `json:",omitempty"`
}
英文:
As shown in the code above, one can use json:",omitempty"
to omit certain fields in a struct to appear in json.
For example
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{},
}
In this case, B
won't show up in json.Marshal(group)
However, if
group := Total{
B:"abc",
}
A
still shows up in json.Marshal(group)
{"A":{"Name":"","Colors":null},"B":"abc"}
Question is how do we get only
{"B":"abc"}
EDIT:
After some googling, here is a suggestion use pointer, in other words, turn Total
into
type Total struct {
A *ColorGroup`json:",omitempty"`
B string`json:",omitempty"`
}
答案1
得分: 65
从文档中可以看到:
结构体值会被编码为JSON对象。除非:
- 字段的标签是“-”,或者
- 字段为空并且其标签指定了“omitempty”选项。
空值包括false、0、任何空指针或接口值,以及长度为零的数组、切片、映射或字符串。
在你声明group
的时候,隐含了group.A
将会是ColorGroup
结构体类型的零值。请注意,在那个被认为是“空值”的列表中,并没有提到结构体类型的零值。
正如你发现的那样,你的情况的解决方法是使用指针。如果在声明group
时不指定A
,这将起作用。如果你将其指定为指向零结构体的指针,那么它将再次出现。
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)
}
英文:
From the documentation:
>Struct values encode as JSON objects. Each exported struct field becomes a member of the object unless
>
>- the field's tag is "-", or
>- the field is empty and its tag specifies the "omitempty" option.
>
>The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero.
In your declaration of group
, it's implicit that group.A
will be the zero value of the ColorGroup
struct type. And notice that zero-values-of-struct-types is not mentioned in that list of things that are considered "empty values".
As you found, the workaround for your case is to use a pointer. This will work if you don't specify A
in your declaration of group
. If you specify it to be a pointer to a zero-struct, then it will show up again.
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
得分: 2
这是一种替代方案,以防您不想使用指向结构体的指针。Container
结构体实现了 json.Marshaller
接口,这使我们可以决定哪些结构体成员应该被省略。
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
}
编辑:添加了文档说明
英文:
This is an alternative solution, in case you would like to avoid using pointers to structs. The Container
struct implements json.Marshaller
, which allows us to decide which members of the strcut should be omitted.
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
}
EDIT: added documentation
答案3
得分: -20
简单的方法
type <name> struct {
<varname> <vartype> `json:"-"`
}
// 示例:
type Boy struct {
name string `json:"-"`
}
这种方式在进行序列化时,name
字段将不会被序列化。
英文:
Easy way
type <name> struct {
< varname > < vartype > \`json : -\`
}
Example :
type Boy struct {
name string \`json : -\`
}
this way on marshaling name
will not get serialized.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论