【问题标题】:Go unmarshal yaml and preserve order去解组 yaml 并保持秩序
【发布时间】:2022-01-19 20:09:38
【问题描述】:

假设我有以下 yaml 文件:

key1:
    - "Value1"
    - "Value2"
key2:
    - "Value3"
    - "Value4"

我想在 Go 中解组它。我可以让 Go 决定该方案的外观并将其打印出来。

m := make(map[interface{}]interface{})
err := yaml.Unmarshal(yaml_file, &m)
fmt.Prinf(m)

这将打印如下内容: map[key1:[Value1 Value2] key2:[Value3 Value4]]

但是地图是无序的。顺序对我来说非常重要,我也不想松开钥匙。

我不能只创建一个结构并尝试将 yaml 文件解组为该结构的一部分...

type Element struct {
    Key   string
    Value interface{}
}

t := []Element{}
err := yaml.Unmarshal(yaml_file, &t)
if err != nil {
    log.Fatalf("error: %v", err)
}

将打印error: yaml: unmarshal errors: line 2: cannot unmarshal !!map into []Element

没有字段标签告诉 yaml 解析器用 yaml 键填充 Key 属性。

有没有比自己编写解码器不同的方法?

【问题讨论】:

    标签: go yaml unmarshalling


    【解决方案1】:

    在我想发布问题之前就找到了答案。

    答案是MapSlice! 您需要从gopkg 导入yaml.v2。 (在撰写本文时,似乎还没有在 yaml.v3 中实现 MapSlices)

    MapSlices 完全实现了我所需要的,并且由许多 MapItems 组成。

    type MapItem struct {
        Key, Value interface{}
    }
    

    所以现在只需解组到 MapSlice。如果您想使用自己的类型,您可以随时转换它,但可能需要进行一些类型转换。

    m := yaml.MapSlice{}
    yaml.Unmarshal(yaml_file, &m)
    
    t := []Element{}
    for _, item := range m {
        t = append(t, Element{item.Key.(string), item.Value})
    }
    

    【讨论】:

    • 我很犹豫是否支持您的回答。虽然它可能对你有用,但我不确定这是否是最好的建议。你应该让你的编码为你工作。如果您关心字段的顺序,那么生成 yaml 的任何内容都应该使用数组。即使您可以以有序的方式读取无序数据,您也不能总是确定无序数据实际上是从一开始就被排序的,特别是如果 yaml 的来源来自 3rd 方服务。虽然您可以准确地说您的 yaml 中的字段是以有序的方式生成的,但对于未来的 Google 员工来说可能并非如此。
    • 我猜你的回答确实正确回答了问题。该类型将按顺序读取字段。但是假设无序的数据是有序的是一个很大的危险信号。
    猜你喜欢
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 2013-07-22
    • 2017-12-23
    • 1970-01-01
    • 2018-04-17
    • 2022-06-13
    • 2017-05-29
    相关资源
    最近更新 更多