我有一个这样的结构体:
type Result struct {
Data MyStruct `json:"data,omitempty"`
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
}
但是,即使MyStruct的示例完全为空(这意味着所有值都是默认值),它也会被序列化为:
"data":{}
我知道encoding/json文档指定“空”字段是:
false、0、任何nil指针或接口值,以及任何长度为零的数组、切片、Map或字符串
但是没有考虑到一个全为空/默认值的结构体。它的所有字段也都用omitempty
标记,但是这没有任何效果。
我怎样才能让JSON包 * 不 * 封送我的空结构体字段?
5条答案
按热度按时间tvz2xvvm1#
正如文档中所说,“any nil pointer.”--使结构体成为指针。指针有明显的“空”值:
nil
。修复-使用struct pointer 字段定义类型:
然后是这样的值:
将编组为:
说明:请注意我们的类型定义中的
*MyStruct
。JSON序列化并不关心它是否是指针-这是运行时细节。因此将结构体字段转换为指针只对编译和运行时有影响。请注意,如果您将字段类型从
MyStruct
更改为*MyStruct
,则需要指向结构体值的指针来填充它,如下所示:pdkcd3nj2#
正如@chakrit在评论中提到的,你不能通过在
MyStruct
上实现json.Marshaler
来实现它,在使用它的每个结构体上实现一个自定义JSON编组函数可能会有更多的工作。这真的取决于你的用例,关于它是否值得额外的工作,或者你是否准备好在JSON中使用空结构体,但下面是我应用于Result
的模式:如果你有一个包含很多字段的巨大结构体,这可能会变得很乏味,特别是以后改变一个结构体的实现,但是如果不重写整个
json
包来满足你的需要(这不是一个好主意),这几乎是我能想到的唯一方法,在那里仍然保留一个非指针MyStruct
。另外,你也不必使用内联结构,你可以创建命名结构。我使用LiteIDE来完成代码,所以我更喜欢内联结构,以避免混乱。
kgqe7b3p3#
Data
是一个初始化的结构体,所以它不被认为是空的,因为encoding/json
只查看立即数,而不是结构体内部的字段。遗憾的是,从
json.Marshaler
返回nil
目前不起作用:您也可以给予
Result
一个封送拆收器,但不值得这样做。正如Matt建议的那样,唯一的选择是将
Data
作为指针,并将值设置为nil
。8gsdolmq4#
有一个优秀的Golang proposal已经活跃了4年多,所以在这一点上,可以肯定的是,它不会很快成为标准库。正如@Matt指出的,传统的方法是将 * struct * 转换为 *pointers-to-struct *。如果这种方法不可行(或不切实际的),则替代方案是使用不支持 * 省略零值结构 * 的替代JSON编码器。
我创建了Golang json库的镜像(clarketm/json),并在应用
omitempty
标记时添加了对 * 省略零值结构 * 的支持。该库通过递归检查 public 结构字段,以与流行的YAML编码器go-yaml类似的方式检测 zeroness。例如
zxlwwiss5#
omitempty
不仅是解决方案,如果你想省略它,那么你必须替换代码对此,
现在omitempty将正常工作谢谢...
另外,假设你想保留条件,比如
oneOf
意味着只允许一个字段填充结构,那么代码看起来像这样,上面的代码只允许您填写1个字段。
例如,如果你正在填充Data1,那么你不能填充Data2和Data3,它会抛出错误