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)似乎只使用InnerUnmarshalJSON而忽略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解组嵌入式结构的主要内容,如果未能解决你的问题,请参考以下文章

MarshallingException:无法解组结果参考

当 JSON 字段键是日期时,如何将 JSON 对象解组为 Golang 结构?

如何解组 JSON?

GOLANG 解组动态 JSON

在不知道结构的情况下解组嵌套的 json

解组忽略空字段