Parsing YAML into a struct in Go can be straightforward. However, when a YAML field can represent multiple possible structs, the task becomes more complex. This article explores a dynamic approach using Go's YAML package.
For Yaml v2, the following approach can be used:
<code class="go">type yamlNode struct { unmarshal func(interface{}) error } func (n *yamlNode) UnmarshalYAML(unmarshal func(interface{}) error) error { n.unmarshal = unmarshal return nil } type Spec struct { Kind string `yaml:"kind"` Spec interface{} `yaml:"-" }</code>
<code class="go">func (s *Spec) UnmarshalYAML(unmarshal func(interface{}) error) error { type S Spec type T struct { S `yaml:",inline"` Spec yamlNode `yaml:"spec"` } obj := &T{} if err := unmarshal(obj); err != nil { return err } *s = Spec(obj.S) switch s.Kind { case "foo": s.Spec = new(Foo) case "bar": s.Spec = new(Bar) default: panic("kind unknown") } return obj.Spec.unmarshal(s.Spec) }</code>
For Yaml v3, the approach is slightly different:
<code class="go">type Spec struct { Kind string `yaml:"kind"` Spec interface{} `yaml:"-" }</code>
<code class="go">func (s *Spec) UnmarshalYAML(n *yaml.Node) error { type S Spec type T struct { *S `yaml:",inline"` Spec yaml.Node `yaml:"spec"` } obj := &T{S: (*S)(s)} if err := n.Decode(obj); err != nil { return err } switch s.Kind { case "foo": s.Spec = new(Foo) case "bar": s.Spec = new(Bar) default: panic("kind unknown") } return obj.Spec.Decode(s.Spec) }</code>
These dynamic unmarshaling techniques allow for flexible parsing of YAML fields into a finite set of structs, providing a more elegant and efficient solution than the proposed workaround. Feel free to explore the provided code snippets and optimize the approach based on your specific requirements.
The above is the detailed content of How to Dynamically Parse a YAML Field into a Finite Set of Structs in Go?. For more information, please follow other related articles on the PHP Chinese website!