【问题标题】:I am trying to unmarshall the following yaml into the below structs, how do I convert the List field into a map field and access it using struct?我正在尝试将以下 yaml 解组为以下结构,如何将 List 字段转换为 map 字段并使用结构访问它?
【发布时间】:2022-01-04 02:23:47
【问题描述】:

YAML 文件:

namespaces:
  - namespace: default
    aliasname: k8s
    components:
      - component: comp1
        replicas: 1
        port: 8080
      - component: comp2
        replicas: 1
        port: 9999
  - namespace: ns2
    components:
      - component: comp1
        replicas: 1

从上面的 YAML 文件中,我想创建如下结构:

type Namespaces struct {
    NamespaceName    string       `yaml:"namespace"`
    Aliasname     string       `yaml:"aliasname,omitempty"`
    ListOfComponents []Components `yaml:"components"`
    ComponentMap     map[string]Components

}

type Components struct {
    ComponentName string `yaml:"component"`
    NumReplicas   int    `yaml:"replicas"`
    Port          int    `yaml:"port"`
}

type Config struct {
    ListOfNamespaces []Namespaces `yaml:"namespaces"`
    NamespaceMap map[string]Namespaces
}

当分别访问confignamespace 对象时,应该能够检索到字段NamespacemapComponentmap。我创建了一个将命名空间和组件列表转换为映射的方法,但是当我调用config.NamespacemapNamespace.ComponentMap 时,它返回一个空映射。

基本上我想知道:我们如何为类型结构添加额外的字段?我想从config 结构访问新变量,例如地图。

更新: 感谢 blami 指导我,但是当我尝试为组件编写相同的内容时,它并没有给我包含组件映射的整个命名空间映射:

type Components struct {
    ComponentName string `yaml:"component"`
    NumReplicas   int    `yaml:"replicas"`
    Port          int    `yaml:"port"`

}

type Namespaces struct {
    NamespaceName string                `yaml:"namespace"`
    Aliasname  string                `yaml:"aliasname"`
    ComponentMap  map[string]Components `yaml:"components"`
}

func (n *Namespaces) UnmarshalYAML(unmarshal func(interface{}) error) error {

    type origNamespace struct {
        ListOfComponents []Components `yaml:"components"`
    }

    var on origNamespace
    err1 := unmarshal(&on)
    if err1 != nil {
        return err1
    }
    n.ComponentMap = make(map[string]Components)
    for _, i := range on.ListOfComponents {
        n.ComponentMap[i.ComponentName] = i
    }

    return nil
}

当我运行 config.NamespaceMap 时,它会给出以下信息

map[:{NamespaceName: K8sNamespace: ComponentMap:map[comp1:{ComponentName:comp1 NumShards:0 NumReplicas:1 Port:0 EpochLength:0}]}]

【问题讨论】:

  • 请考虑解决这个问题。 “我正在尝试将以下 yaml 解组为一个结构,该结构具有我可以与结构一起访问的额外字段映射?”对我来说看起来不像一个句子。
  • 嗨,我已经编辑了问题,如果需要进一步编辑,请告诉我。
  • 能否在问题中包含您引用的代码/方法

标签: go struct hashmap yaml unmarshalling


【解决方案1】:

如果你想进行这样的转换,你需要在 ConfigNamespace 类型上编写一个自定义的 UnmarshalYAML() 接收器。这是这样做的基本工作示例(仅适用于“命名空间”):

type Config struct {
    Namespaces map[string]Namespace `yaml:"namespaces"`
}

// Replace go-yaml built-in unmarshaller with custom that will transform list to map.
// Note this code is meant only as demonstration!
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
    type origConfig struct {
        Namespaces []Namespace `yaml:"namespaces"`
    }
    var o origConfig
    err := unmarshal(&o)
    if err != nil {
        return err
    }

    // Assign namespaces in list to map; namespaces with same name will be overwritten
    c.Namespaces = make(map[string]Namespace)
    for _, n := range o.Namespaces {
        c.Namespaces[n.Namespace] = n
    }
    return nil
}

// You can use "Config" type as usual
func main() {
    var config Config
    err := yaml.Unmarshal(<your_yaml>, &config)
    if err != nil {
        log.Panic(err)
    }
    fmt.Println(config.Namespaces)
    // map[default:{default k8s} ns2:{ns2 }]
    fmt.Printf("%v\n", config.Namespaces["default"])
    // {default k8s}
}

如代码示例中所述,这将导致一些问题(例如,如果命名空间名称相同怎么办?)。

游乐场链接:https://go.dev/play/p/IKg8kmRnknq

【讨论】:

  • 谢谢,这是我想要的,让我也添加到组件中,这也是标准的方式吗?由于我是 golang 新手,我只想知道这是否是标准方法,但这绝对是我问题的答案。
  • 对不遵循 YAML 结构的自定义类型使用自定义 UnmarshalYAML() 接收器几乎是仿照标准库 json 包的标准方法。尽管我看到的大多数项目都只是尝试坚持使用原始 YAML/JSON 结构——在这种情况下,除非真的不方便,否则会列出命名空间。
  • 你能看看更新@blami
  • @Niharika 您的代码只查看组件字段。当您覆盖 UnmarshalYAML() 接收器时,您应对一切负责。所以你需要处理所有领域。代码中还有一个小BUG,它为每个组件创建新的组件映射,这将覆盖以前的组件。我将固定代码添加到 go.dev/play/p/Boq_2Kku8-C 。正如您所看到的,维护这些地图可能会变得乏味且容易出错 - 这就是为什么最好坚持使用任何原始文件结构。
  • 非常感谢所有的更正,我一直在思考为什么我得到一个空的命名空间映射,是的,我理解我遇到的错误。让我试试看我是否真的可以坚持原来的 yaml 文件。
猜你喜欢
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 2021-06-28
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 2020-10-14
相关资源
最近更新 更多