问题
I would like to unmarshal to struct Outer
defined as:
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
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.
Thanks!
回答1:
This is happening because Inner
is being embedded in Outer
. That means when json library calls unmarshaler on Outer
, it instead ends up calling it on 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.
You can fix this by making Inner
explicit field in Outer
Outer struct {
I Inner // make Inner an explicit field
Num int `json:"Num"`
}
Working example
回答2:
You shouldn't need an unmarshalling function
https://play.golang.org/p/-HZwX5-rPD
Edit: Here is a more complete example
https://play.golang.org/p/oz5kiwy3_K
回答3:
Just delete UnmarshalJSON
in your example because it's used in unmarshaling of Outer
since Inner
is inlined. Otherwise, you need to override it if you want to do something custom.
https://play.golang.org/p/D6V6vKpx9J
回答4:
Actually you not need explicit field, you need properly Marshal/UnMarshal
Example: 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))
}
来源:https://stackoverflow.com/questions/38982445/json-unmarshal-embedded-struct