猿问

如何解析 YAML 文件并从父结构创建子对象(继承)

假设我有以下结构:


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 吗?


catspeake
浏览 448回答 1
1回答

斯蒂芬大帝

您的类型错误,Go 没有继承。您不能将类型的值存储到类型*Mercedes的*BMW数组中[]*Car;两种类型都只包含一个Car值作为 mixin。要做你想做的事,你必须把你的Car类型变成一个界面。现在是 YAML 部分:您可以将 YAML 结构的一部分存储在一个类型的对象中,yaml.Node然后再对其进行反序列化。您可以通过实现UnmarshalYAML(从yaml.Unmarshaler接口)来实现自定义解组器。所以我们要做的是实现一个自定义解组器,CarShop它将周围的结构反序列化为一个列表,其中包含从汽车类型到yaml.Node(该类型的值)的映射,然后根据给定的汽车类型,将每个节点反序列化为适当的类型。这是它的外观:package mainimport (    "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.Nodefunc (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("---")    }}
随时随地看视频慕课网APP

相关分类

Go
我要回答