【问题标题】:How to parse YAML file and create child-objects from parent struct (inheritance)如何解析 YAML 文件并从父结构创建子对象(继承)
【发布时间】:2020-01-17 23:19:39
【问题描述】:

假设我有以下结构:

type CarShop struct {
  Cars []*Car
}

type Car struct {
  ID string `yaml:“id“`
}

type BMW struct {
  Car
  A string `yaml:“a“`
}

type Mercedes struct {
  Car
  B string `yaml:“b“
}

我想解析以下字符串:

- BMW:
    id: „BMW“
    a: „a“
- Mercedes:
    id: „Mercedes“
    b: „b“

如何动态创建解析此字符串的 BMW 和 Mercedes 对象?这甚至可以使用 Go 和 go-yaml 实现吗?

【问题讨论】:

  • 你试过用 Car 实现 Unmarshaler 接口吗?
  • 感谢您的建议!我认为 flyx 的评论很好地说明了这种实现。

标签: go inheritance yaml


【解决方案1】:

您的类型错误,Go 没有继承。您不能将 *Mercedes*BMW 类型的值存储到 []*Car 类型的数组中;这两种类型都只是 include 一个 Car 值作为 mixin。要做你想做的事,你必须把你的Car类型改成一个界面。

现在是 YAML 部分:您可以将 YAML 结构的一部分存储在 yaml.Node 类型的对象中,然后再对其进行反序列化。您可以通过实现UnmarshalYAML(来自yaml.Unmarshaler 接口)来实现自定义解组器。所以我们要做的是为CarShop 实现一个自定义解组器,它将周围的结构反序列化为一个列表,其中包含从汽车类型到yaml.Node(该类型的值)的映射,然后取决于给定的汽车类型,将每个节点反序列化为正确的类型。下面是它的外观:

package main

import (
    "errors"
    "fmt"
    "gopkg.in/yaml.v3"
)

type CarShop struct {
    Cars []Car
}

type Car interface {
    ID() string
}

type BMW struct {
    IDVal string `yaml:"id"`
    A     string `yaml:"a"`
}

func (bmw *BMW) ID() string {
    return bmw.IDVal
}

type Mercedes struct {
    IDVal string `yaml:"id"`
    B     string `yaml:"b"`
}

func (merc *Mercedes) ID() string {
    return merc.IDVal
}

type tmpCarShop []map[string]yaml.Node

func (cs *CarShop) UnmarshalYAML(value *yaml.Node) error {
    var tmp tmpCarShop
    if err := value.Decode(&tmp); err != nil {
        return err
    }
    cars := make([]Car, 0, len(tmp))
    for i := range tmp {
        for kind, raw := range tmp[i] {
            switch kind {
            case "Mercedes":
                m := &Mercedes{}
                if err := raw.Decode(m); err != nil {
                    return err
                }
                cars = append(cars, m)
            case "BMW":
                b := &BMW{}
                if err := raw.Decode(b); err != nil {
                    return err
                }
                cars = append(cars, b)
            default:
                return errors.New("unknown car type: " + kind)
            }
        }
    }
    cs.Cars = cars
    return nil
}

func main() {
    input := []byte(`
- BMW:
    id: "BMW"
    a: "a"
- Mercedes:
    id: "Mercedes"
    b: "b"
`)

    var shop CarShop
    if err := yaml.Unmarshal(input, &shop); err != nil {
        panic(err)
    }

    for i := range shop.Cars {
        fmt.Printf("ID: %s\n", shop.Cars[i].ID())
        switch c := shop.Cars[i].(type) {
        case *Mercedes:
            fmt.Printf("Type: Mercedes\nA: %s\n", c.B)
        case *BMW:
            fmt.Printf("Type: BMW\nB: %s\n", c.A)
        }
        fmt.Println("---")
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    相关资源
    最近更新 更多