json 解组嵌入式结构
json unmarshal embedded 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
字段,但我想知道是否有人有更干净或更简单的方法来做到这一点。
谢谢!
这是因为 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"`
}
只需在您的示例中删除 UnmarshalJSON
,因为它用于 Outer
的解组,因为 Inner
是内联的。否则,如果你想做一些自定义的事情,你需要覆盖它。
其实你不需要明确的领域,你需要适当的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))
}
一种方法是完全放弃自定义 UnmarshalJSON
函数,只使用基本的 JSON 表示法,即:
type Outer struct {
Inner
Num int `json:"num"`
}
type Inner struct {
Data string `json:"data"`
}
您失去了一些使用自定义解组方法可能拥有的更精细的功能,但是当您解组一个主要包含字符串等原始字段的结构时,您真的不需要担心这一点。
如果您确实需要自定义解组,您可以使用组合,并为结构提供自定义 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"`
}
再说一次,它没有自定义解组功能,但可以很容易地将其拼凑在一起 Inner
。 (就个人而言,我会在任何给定情况下完全放弃使用自定义解组函数,而只使用编码标签,除非我绝对必须使用解组函数。)
面临同样的问题。一种解决方案是为每个子结构解组两次。例如
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)
}
这需要将额外的字段移动到一个单独的结构中。
我想解组结构 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
字段,但我想知道是否有人有更干净或更简单的方法来做到这一点。
谢谢!
这是因为 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"`
}
只需在您的示例中删除 UnmarshalJSON
,因为它用于 Outer
的解组,因为 Inner
是内联的。否则,如果你想做一些自定义的事情,你需要覆盖它。
其实你不需要明确的领域,你需要适当的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))
}
一种方法是完全放弃自定义 UnmarshalJSON
函数,只使用基本的 JSON 表示法,即:
type Outer struct {
Inner
Num int `json:"num"`
}
type Inner struct {
Data string `json:"data"`
}
您失去了一些使用自定义解组方法可能拥有的更精细的功能,但是当您解组一个主要包含字符串等原始字段的结构时,您真的不需要担心这一点。
如果您确实需要自定义解组,您可以使用组合,并为结构提供自定义 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"`
}
再说一次,它没有自定义解组功能,但可以很容易地将其拼凑在一起 Inner
。 (就个人而言,我会在任何给定情况下完全放弃使用自定义解组函数,而只使用编码标签,除非我绝对必须使用解组函数。)
面临同样的问题。一种解决方案是为每个子结构解组两次。例如
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)
}
这需要将额外的字段移动到一个单独的结构中。