json解组嵌入式结构
Posted
技术标签:
【中文标题】json解组嵌入式结构【英文标题】:json unmarshal embedded struct 【发布时间】:2016-12-23 06:34:37 【问题描述】:我想解组 struct Outer
定义为:
type Outer struct
Inner
Num int
type Inner struct
Data string
func (i *Inner) UnmarshalJSON(data []byte) error
i.Data = string(data)
return nil
使用json.Unmarshal(data, &Outer)
似乎只使用Inner
的UnmarshalJSON
而忽略Num
字段:https://play.golang.org/p/WUBfzpheMl
我有一个笨拙的solution,我在其中手动设置了Num
字段,但我想知道是否有人有更简洁或更简单的方法。
谢谢!
【问题讨论】:
请注意,原因在Go语言参考的这部分解释:golang.org/ref/spec#Struct_types(查找单词“promoted”) 【参考方案1】:这是因为Inner
被嵌入到Outer
中。这意味着当 json 库在 Outer
上调用 unmarshaler 时,它最终会在 Inner
上调用它。
因此,在 func (i *Inner) UnmarshalJSON(data []byte)
内部,data
参数包含整个 json 字符串,然后您将只为 Inner
处理它。
您可以通过在 Outer
中设置 Inner
显式字段来解决此问题
Outer struct
I Inner // make Inner an explicit field
Num int `json:"Num"`
Working example
【讨论】:
感谢您的解释! 当然,这解决了无法解组Num
的问题,但是,它不适用于"data": "test", "num": 1
之类的嵌入数据,它只能用于"inner": "data": "test", "num": 1
之类的数据。跨度>
同意埃里克。我认为这个答案仅在这种情况下几乎不适用,但在一般情况下它具有误导性。
这是一个误导性的答案。我知道这个问题本身有点不清楚,但建议的解决方案与嵌入式类型无关。【参考方案2】:
只需删除示例中的UnmarshalJSON
,因为它用于Outer
的解组,因为Inner
是内联的。否则,如果你想做一些自定义的事情,你需要覆盖它。
https://play.golang.org/p/D6V6vKpx9J
【讨论】:
【参考方案3】:一种方法是完全放弃自定义 UnmarshalJSON
函数,而只使用基本的 JSON 表示法,即:
type Outer struct
Inner
Num int `json:"num"`
type Inner struct
Data string `json:"data"`
您会失去一些使用自定义解组方法可以拥有的更精细的功能,但是当您解组具有大部分原始字段(如字符串)的结构时,您真的不需要担心这一点。
Example in go playground
如果你真的需要自定义解组,你可以使用组合,给结构一个自定义的 json 编码标签,让结构包含你想要玩的字段。因此,如果 data
包含多个复杂字段,您只需更改 Inner
以反映这些字段,如下所示:
type Outer struct
Data Inner `json:"data"`
Num int `json:"num"`
type Inner struct
Thing string `json:"thing"`
OtherThing int `json:"otherThing"`
Example in go playground
再一次,它没有自定义解组功能,但可以很容易地为Inner
拼凑起来。 (就个人而言,在任何给定情况下,我都会完全放弃使用自定义解组函数,而只使用编码标签,除非我绝对必须使用解组函数。)
【讨论】:
【参考方案4】:其实你不需要显式字段,你需要正确的 Marshal/UnMarshal
示例:https://play.golang.org/p/mWPM7m44wfK
package main
import (
"encoding/json"
"fmt"
)
type Outer struct
Inner
Num int `json:"Num"`
type Inner struct Data string
type InnerRaw struct Data string
func (i *Inner) UnmarshalJSON(data []byte) error
ir:=&InnerRaw
json.Unmarshal(data, ir)
i.Data = ir.Data
return nil
func main()
x := Outer
data := []byte(`"Num": 4, "Data":"234"`)
_ = json.Unmarshal(data, &x)
fmt.Printf("%+v\n", x)
js, _:=json.Marshal(x)
fmt.Printf("JSON:%s", string(js))
【讨论】:
但是Num
仍然是0,尽管它应该是4
嗯,是的,我们可以删除 InnerRaw 结构和 UnmarshallJSON 函数。结果:play.golang.org/p/JkKCLQOnsHp 工作正常
当内部有 UnmarshalJSON
时,OP 想要解析 Num
。如果我们删除UnmarshalJSON
,那么它不会回答问题以上是关于json解组嵌入式结构的主要内容,如果未能解决你的问题,请参考以下文章