【问题标题】:json unmarshal embedded structjson解组嵌入式结构
【发布时间】: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{})似乎只使用InnerUnmarshalJSON而忽略Num字段:https://play.golang.org/p/WUBfzpheMl

我有一个笨拙的solution,我在其中手动设置了Num 字段,但我想知道是否有人有更简洁或更简单的方法。

谢谢!

【问题讨论】:

标签: json go unmarshalling


【解决方案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,那么它不会回答问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多