简体   繁体   English

json解组嵌入式结构

[英]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{})似乎只使用InnerUnmarshalJSON并忽略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"`
}

Working example工作示例

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM