I am trying to iterate over a map of interfaces in golang, it has the below structure, I am able to use for loop to iterate to a single level but couldn't go deep to get values of the interface.
Yaml
steps:
execute:
- mvn : 1.9.3
goals: 'clean install'
concurrent: false
- mvn : 1.9.3
goals: 'dependency-check:check'
concurrent: false
Go
// 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)
}
Output of
fmt.Printf("--- m:\n%v\n\n", m)
looks like below
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]]]]
My attempt
for k, v := range m {
fmt.Println("k:", k, "v:", v)
}
To access the Execute object and iterate over it you have to do a lot of type assertions like the answer given by @vooker.
Actually it's not recommended to use map[interface{}]interface{}
for unmarshaling process. It should be unmarshalled to a concrete type as a struct.
From the YAML structure, it could be translated as a struct type like this:
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"`
}
And from the structure, it is easier to access the unmarshalled data from the YAML. For example, if you want to iterate over the "execute" object you could do something like this:
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)
}
Try it on the playground