为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
catspeake 2022-05-05 17:53:55
假设我有以下结构: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 吗?
查看完整描述

1 回答

?
斯蒂芬大帝

TA贡献1827条经验 获得超8个赞

您的类型错误,Go 没有继承。您不能将类型的值存储到类型*Mercedes的*BMW数组中[]*Car;两种类型都只包含一个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("---")

    }

}


查看完整回答
反对 回复 2022-05-05
  • 1 回答
  • 0 关注
  • 447 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信