【问题标题】:Load a YAML files with a list of items of different structs加载包含不同结构项目列表的 YAML 文件
【发布时间】:2020-09-16 17:02:26
【问题描述】:

我有一个格式如下的 YAML:

actions:
  - type: one
    onekey: value
  - type: two
    twokey: value
    foo: bar

我想将它加载到 Go 结构中。我尝试将mapstructursDecodeHook 一起使用,但我无法让它工作。

这是我尝试过的:

type Actions struct {
    actions []Action
}

type Action interface {
}

type One struct {
    Onekey string
}

type Two struct {
    Twokey string
    Foo    string
}

var actions Actions

func Load() {
...
    config := &mapstructure.DecoderConfig{
        DecodeHook: func(sourceType, destType reflect.Type, raw interface{}) (interface{}, error) {
            if fmt.Sprintf("%s", destType) == "Action" {
                var result Action

                switch raw.(map[string]interface{})["type"] {
                case "one":
                    result = One{}
                case "two":
                    result = Two{}
                }
                mapstructure.Decode(raw, &result)
                return result, nil
            }
            return raw, nil
        },
        Result: &actions,
    }
...
}

这很丑陋,也不起作用。我明白了:

panic: interface conversion: interface {} is map[interface {}]interface {}, not map[string]interface {}

首先是:

if fmt.Sprintf("%s", destType) == "Action"

这很可怕,但我让这部分工作的唯一方法。

然后是读取列表项并通过type 键将其转换为正确的结构。有没有办法让这个工作?

谢谢!

【问题讨论】:

    标签: go yaml


    【解决方案1】:

    最后我采用了这种方法:

        config := &mapstructure.DecoderConfig{
            DecodeHook: func(sourceType, destType reflect.Type, raw interface{}) (interface{}, error) {
                var result Action
                if fmt.Sprintf("%s", destType) == "Action" {
                    rawMap := raw.(map[interface{}]interface{})
                    switch rawMap["type"] {
                    case "one":
                        result = One{}
                    case "two":
                        result = Two{}
                    }
    
                    mapstructure.Decode(raw, &result)
                    return result, nil
                }
                return raw, nil
            },
            Result: &actions,
        }
    

    我只是从 Go 开始,所以可能有更好的方法,但这有点解决了我遇到的两个问题。

    更正:由于reflect.TypeOf(result) == nil,我不得不恢复为if fmt.Sprintf("%s", destType) == "Action"

    【讨论】:

      【解决方案2】:

      看看 viper 包:https://github.com/spf13/viper 它可以让你从 toml、json yaml 等文件中读取,然后你可以将每个配置值传递给你的结构。

      【讨论】:

      • 我不太明白 viper 如何帮助我处理包含不同类型的列表...
      猜你喜欢
      • 1970-01-01
      • 2020-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 2017-08-04
      • 1970-01-01
      • 2021-06-09
      相关资源
      最近更新 更多