gogo-interfacego-map

Golang iterate over map of interfaces


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)

}

Solution

  • 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