将YAML字段动态解析为围棋中有限组结构中的一个 [英] Dynamically parse yaml field to one of a finite set of structs in Go

查看:20
本文介绍了将YAML字段动态解析为围棋中有限组结构中的一个的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个yaml文件,其中一个字段可以由一种可能的结构表示。为了简化代码和YAML文件,假设我有以下YAML文件:

kind: "foo"
spec:
  fooVal: 4
kind: "bar"
spec:
  barVal: 5

和这些用于解析的结构:

    type Spec struct {
        Kind string      `yaml:"kind"`
        Spec interface{} `yaml:"spec"`
    }
    type Foo struct {
        FooVal int `yaml:"fooVal"`
    }
    type Bar struct {
        BarVal int `yaml:"barVal"`
    }
我知道我可以将map[string]interface{}用作Spec字段的一种类型。但真正的示例更复杂,涉及更多可能的结构类型,不仅是FooBar,这就是我不喜欢将spec解析到字段中的原因。

我找到了一个解决方法:将YAML解组为中间结构,然后检查kind字段,将map[string]interface{}字段重新编组为YAML,并将其解组为具体类型:

    var spec Spec
    if err := yaml.Unmarshal([]byte(src), &spec); err != nil {
        panic(err)
    }
    tmp, _ := yaml.Marshal(spec.Spec)
    if spec.Kind == "foo" {
        var foo Foo
        yaml.Unmarshal(tmp, &foo)
        fmt.Printf("foo value is %d
", foo.FooVal)
    }
    if spec.Kind == "bar" {
        tmp, _ := yaml.Marshal(spec.Spec)
        var bar Bar
        yaml.Unmarshal(tmp, &bar)
        fmt.Printf("bar value is %d
", bar.BarVal)
    }

但它需要额外的步骤和消耗更多的内存(实际的YAML文件可能比示例中的大)。有没有更好的方法来动态地将YAML解组为有限的结构集?

更新:我正在使用github.com/go-yaml/yaml v2.1.0YAML解析器。

推荐答案

要与yaml.v2一起使用,您可以执行以下操作:

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:"-"`
}
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)
}

https://play.golang.org/p/Ov0cOaedb-x


要与yaml.v3一起使用,您可以执行以下操作:

type Spec struct {
    Kind string      `yaml:"kind"`
    Spec interface{} `yaml:"-"`
}
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)
}

https://play.golang.org/p/ryEuHyU-M2Z

这篇关于将YAML字段动态解析为围棋中有限组结构中的一个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆