How do you dynamically parse YAML fields into specific structs in Go without using an intermediate map?

Linda Hamilton
Release: 2024-10-31 01:47:01
Original
628 people have browsed it

How do you dynamically parse YAML fields into specific structs in Go without using an intermediate map?

Dynamically Parsing YAML Fields to Specific Structs in Go

Determining the optimal approach to dynamically parse YAML fields into predefined structs can be a common challenge in Go. Let's examine the provided scenario and explore the best options available.

The Challenge

Given YAML files with varying content and a set of structs representing different data types, the goal is to dynamically parse these fields into the appropriate structs. The provided approach involves using an intermediate map, but a more elegant solution is sought.

Solution

Utilizing the YAML v2.1.0 Yaml parser, here's an improved approach:

<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>
Copy after login
<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>
Copy after login

This solution elegantly handles the dynamic parsing by embedding the struct's kind and spec field in the T type. The yamlNode type facilitates the unmarshaling of the Spec interface, allowing for the selection of the appropriate concrete struct.

Updated Approaches for YAML v3

For YAML v3, a similar approach can be used, with minor adjustments:

<code class="go">type Spec struct {
    Kind string      `yaml:"kind"`
    Spec interface{} `yaml:"-"`
}</code>
Copy after login
<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>
Copy after login

These updated approaches provide a more direct and efficient method for dynamically parsing YAML fields into the desired struct types without the need for intermediate maps or additional steps.

The above is the detailed content of How do you dynamically parse YAML fields into specific structs in Go without using an intermediate map?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!