0

我正在尝试迭代 golang 中的接口映射,它具有以下结构,我可以使用 for 循环迭代到单个级别,但无法深入获取接口的值。

yaml

steps:
  execute:
  - mvn : 1.9.3
    goals: 'clean install'
    concurrent: false
  - mvn : 1.9.3
    goals: 'dependency-check:check'
    concurrent: false

// reading a yaml file 
// trying to use "gopkg.in/yaml.v2" package

data, err := ioutil.ReadFile(fileName)
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
    for k, v := range m {
       // Trying to explore the data here
        fmt.Println("k:", k, "v:", v)

    }

的输出

fmt.Printf("--- m:\n%v\n\n", m)

如下所示

map[steps:map[execute:[map[concurrent:false goals:clean install mvn:1.9.3] map[concurrent:false goals:dependency-check:check mvn:1.9.3]]]]

我的尝试

for k, v := range m {
    fmt.Println("k:", k, "v:", v)

}
4

3 回答 3

3

假设您有一个 map[interface{}]interface{} 和 []interface{} 树,使用以下代码遍历树:

func walk(v interface{}) {
    switch v := v.(type) {
    case []interface{}:
        for i, v := range v {
            fmt.Println("index:", i)
            walk(v)
        }
    case map[interface{}]interface{}:
        for k, v := range v {
            fmt.Println("key:", k)
            walk(v)
        }
    default:
        fmt.Println(v)
    }
}

此代码向下递归结构并使用类型开关来查找切片和映射。

像这样使用它:

data, err := ioutil.ReadFile(fileName)
var m map[interface{}]interface{}
err = yaml.Unmarshal([]byte(data), &m)
walk(m)

在操场上跑

于 2020-07-21T01:16:49.383 回答
1

我不知道你所说的“m 的值”是什么意思,因为它看起来不像我在 Go 中看到的任何格式,所以我将讨论几种情况:当接口可能是类型时,你知道它们是什么是与何时接口可以是任何东西而你不确定。

如果您知道地图中只有几种类型,您可以进行类型切换并单独处理每种类型。这将使您有机会引用子字段并打印它们。如果您总是为相同类型的对象打印相同的信息,您可以考虑String() string向您的结构添加一个函数,这将使它们实现Stringer接口,然后您可以打印该对象并且您的 String() 函数将被调用,即使它是装箱为界面。

如果您正在使用一个正在填充地图的库,或者地图中的类型种类太多以至于类型切换不合理,那么您将需要一个通用解决方案,例如spew之类的库或用反射编写的自定义解决方案。

于 2020-07-21T01:12:29.497 回答
1

要访问 Execute 对象并对其进行迭代,您必须执行许多类型断言,例如@vooker 给出的答案。

实际上不建议map[interface{}]interface{}用于解组过程。它应该作为结构解组为具体类型。

从 YAML 结构中,它可以被翻译成这样的结构类型:


type data struct {
    Steps struct {
        Execute []execute `yaml:"execute"`
    } `yaml:"steps"`
}

type execute struct {
    MVN        string `yaml:"mvn"`
    Goals      string `yaml:"goals"`
    Concurrent bool   `yaml:"concurrent"`
}

而且从结构上来说,从 YAML 中访问未编组的数据更容易。例如,如果您想遍历“执行”对象,您可以执行以下操作:

    var result data
    yaml.Unmarshal([]byte(str), &result)
    fmt.Println(result) 

    // iterate over the slice of object
    for _, e := range result.Steps.Execute {
        fmt.Println()
        fmt.Println("mvn:", e.MVN)
        fmt.Println("goals:", e.Goals)
        fmt.Println("concurrent:", e.Concurrent)
    }

在操场上试试

于 2020-07-21T03:52:45.623 回答