Ваши типы ошибочны, 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("---")
}
}