Как разобрать файл YAML и создать дочерние объекты из родительской структуры (наследование) - PullRequest
1 голос
/ 18 января 2020

давайте предположим, что у меня есть следующие структуры:

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 и Мерседесы разбирают эту строку? Это возможно даже при использовании Go и go -yaml?

1 Ответ

0 голосов
/ 18 января 2020

Ваши типы ошибочны, Go не имеет наследства. Вы не можете сохранить значение типа *Mercedes или *BMW в массиве типа []*Car; оба типа просто включают a Car значение как миксин. Чтобы сделать то, что вы хотите, вы должны изменить свой тип Car на интерфейс.

Теперь для части YAML: Вы можете сохранить часть своей структуры YAML внутри объекта типа yaml.Node и десериализовать это позже. Вы можете реализовать собственный unmarshaler, внедрив 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("---")
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...