Description
I am trying to use an interface{}
field on a struct to unmarshal into arbitrary struct types using a single field. I'd like to know if the behavior i'm seeing is expected or if there is a different way to accomplish this. I've linked to an example on the Go Playground but will include a few excerpts.
I have a few structs, for example:
type Envelope struct {
Data interface{} `yaml:"data"`
}
type Foo struct {
Greeting string `yaml:"greeting"`
}
type Bar struct {
Farewell string `yaml:"farewell"`
}
And I'm trying to support these configs, as an example:
---
data:
greeting: "Hello from YAML"`
---
data:
farewell: "Goodbye from YAML"
I would expect to be able to unmarshal one of those configs using an Envelope
with a pointer to Foo
or Bar
resulting in the fields on Foo
or Bar
being set to the values in the configuration. Instead, Data
on Envelope
is a map[string]interface{}
.
For example:
var foo Foo
envelope := Envelope{
Data: &foo,
}
err := yaml.Unmarshal([]byte(yamlPayload), &envelope)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", envelope) // main.Envelope{Data:map[string]interface {}{"greeting":"Hello from YAML"}}
fmt.Printf("%#v\n", envelope.Data) // map[string]interface {}{"greeting":"Hello from YAML"}
I would have expected this to print the following:
main.Envelope{Data:(*main.Foo)(0xc000010280)}
&main.Foo{Greeting:"Hello from YAML"}
The unmarshalling doesn't respect the point to the struct set on the interface field and overwrites it with map[string]interface{}
The playground link shows a complete example and includes an example with this behavior from the encdoing/json
Unmarshal function, which gives the desired results.
Playground Link