[英]json unmarshal embedded struct
I would like to unmarshal to struct Outer
defined as:我想解组到 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
}
Using json.Unmarshal(data, &Outer{})
seems only to use Inner
's UnmarshalJSON
and ignores the Num
field: https://play.golang.org/p/WUBfzpheMl使用
json.Unmarshal(data, &Outer{})
似乎只使用Inner
的UnmarshalJSON
并忽略Num
字段:https: //play.golang.org/p/WUBfzpheMl
I have an unwieldy solution where I set the Num
field manually, but I was wondering if anybody had a cleaner or simpler way to do it.我有一个笨拙的解决方案,我手动设置
Num
字段,但我想知道是否有人有更清洁或更简单的方法来做到这一点。
Thanks!谢谢!
This is happening because Inner
is being embedded in Outer
.发生这种情况是因为
Inner
被嵌入到Outer
中。 That means when json library calls unmarshaler on Outer
, it instead ends up calling it on Inner
.这意味着当 json 库在
Outer
上调用 unmarshaler 时,它最终会在Inner
上调用它。
Therefore, inside func (i *Inner) UnmarshalJSON(data []byte)
, the data
argument contains the entire json string, which you are then processing for Inner
only.因此,在
func (i *Inner) UnmarshalJSON(data []byte)
, data
参数包含整个 json 字符串,然后您只为Inner
处理它。
You can fix this by making Inner
explicit field in Outer
您可以通过在
Outer
中设置Inner
显式字段来解决此问题
Outer struct {
I Inner // make Inner an explicit field
Num int `json:"Num"`
}
You shouldn't need an unmarshalling function 你不应该需要一个解组函数
https://play.golang.org/p/-HZwX5-rPD https://play.golang.org/p/-HZwX5-rPD
Edit: Here is a more complete example 编辑:这是一个更完整的例子
https://play.golang.org/p/oz5kiwy3_K https://play.golang.org/p/oz5kiwy3_K
Just delete UnmarshalJSON
in your example because it's used in unmarshaling of Outer
since Inner
is inlined.只需在您的示例中删除
UnmarshalJSON
,因为它用于Outer
的解组,因为Inner
是内联的。 Otherwise, you need to override it if you want to do something custom.否则,如果你想做一些自定义的事情,你需要覆盖它。
https://play.golang.org/p/D6V6vKpx9J https://play.golang.org/p/D6V6vKpx9J
One way to do this is to forgo the custom UnmarshalJSON
function entirely and just use the basic JSON notation, ie:一种方法是完全放弃自定义
UnmarshalJSON
函数,而只使用基本的 JSON 表示法,即:
type Outer struct {
Inner
Num int `json:"num"`
}
type Inner struct {
Data string `json:"data"`
}
You lose some of the more granular capabilities you could have with a custom unmarshalling method, but when you're unmarshalling a struct with mostly primitive fields like strings, you really don't need to worry about that.您失去了使用自定义解组方法可能拥有的一些更精细的功能,但是当您解组具有大部分原始字段(如字符串)的结构时,您真的不需要担心这一点。
Example in go playground去游乐场的例子
If you really need custom unmarshalling, you could use composition, and give the struct a custom json encoding tag and have the struct contain the fields you want to play with.如果你真的需要自定义解组,你可以使用组合,并给结构一个自定义的 json 编码标签,并让结构包含你想要玩的字段。 So if
data
is something that will contain multiple complex fields, you could just change Inner
to reflect those fields, like this:因此,如果
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去游乐场的例子
Once again, this doesn't have a custom unmarshalling function, but that can be scraped together for Inner
easily enough.再一次,它没有自定义的解组功能,但可以很容易地为
Inner
拼凑起来。 (Personally, I'd forgo the use of custom unmarshal functions entirely in any given case and just use encoding tags unless I absolutely had to use the unmarshalling function.) (就个人而言,我会在任何给定情况下完全放弃使用自定义解组函数,而只使用编码标签,除非我绝对必须使用解组函数。)
Faced same issue.面临同样的问题。 One solution is to unmarshal twice for each sub structs.
一种解决方案是为每个子结构解组两次。 Eg
例如
type Inner struct {
Data string
}
type NumField struct {
Num int
}
type Outer struct {
Inner
NumField
}
func (i *Inner) UnmarshalJSON(data []byte) error {
i.Data = string(data)
return nil
}
func (o *Outer) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &o.Inner); err != nil {
return err
}
if err := json.Unmarshal(data, &o.NumField); err != nil {
return err
}
return nil
}
func main() {
x := Outer{}
data := []byte(`{"Num": 4}`)
_ = json.Unmarshal(data, &x)
fmt.Printf("%#v\n", x)
}
This requires moving the extra fields into a separate struct.这需要将额外的字段移动到单独的结构中。
Actually you not need explicit field, you need properly Marshal/UnMarshal实际上你不需要显式字段,你需要正确的 Marshal/UnMarshal
Example: https://play.golang.org/p/mWPM7m44wfK示例: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))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.