英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论