0
votes

Golang itérer sur la carte des interfaces

J'essaie d'itérer sur une carte d'interfaces dans golang, elle a la structure ci-dessous, je peux utiliser la boucle for pour itérer à un seul niveau mais je n'ai pas pu aller plus loin pour obtenir les valeurs de l'interface.

Yaml

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

}

Allez

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]]]]

La sortie de

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

ressemble à ci-dessous

// 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)

    }

Ma tentative

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


0 commentaires

3 Réponses :


1
votes

Je ne sais pas ce que vous voulez dire avec cette "valeur de m" car cela ne ressemble à aucun format que j'ai vu dans Go, je vais donc parler de quelques situations: lorsque les interfaces sont probablement des types vous sachez ce qu'elles sont ou quand les interfaces pourraient être n'importe quoi et vous n'êtes pas sûr.

Si vous savez que seuls quelques types sont entrés dans la carte, vous pouvez faire un type commutateur et manipulez chaque type individuellement. Cela vous donnerait la possibilité de référencer des sous-champs et de les imprimer également. Si vous imprimez toujours les mêmes informations pour le même type d'objets, vous pouvez envisager d'ajouter une fonction String () string à vos structures qui leur fera implémenter le Stringer interface et ensuite vous pouvez imprimer l'objet et votre func String () sera appelée même si elle est encadrée comme interface.

Si vous travaillez avec une bibliothèque qui remplit la carte, ou s'il y a simplement une trop grande diversité de types dans la carte pour qu'un changement de type soit raisonnable, alors vous voudrez soit une solution générique telle qu'une bibliothèque comme spew ou une solution personnalisée écrite avec reflexion .


1 commentaires

Excusez-vous, j'aurais dû être plus clair. J'ai édité la question. Merci.



2
votes

En supposant que vous ayez une arborescence de la carte [interface {}] interface {} et [] interface {}, utilisez le code suivant pour parcourir l'arborescence:

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

Ce code se répète vers le bas la structure et utilise des commutateurs de type pour trouver les tranches et les cartes.

Utilisez-le comme ceci:

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)
    }
}

Exécutez-le sur le aire de jeux


0 commentaires

1
votes

Pour accéder à l'objet Execute et l'itérer, vous devez effectuer de nombreuses assertions de type comme la réponse donnée par @vooker.

En fait, il n'est pas recommandé d'utiliser map [interface {}] interface {} pour le processus de démarshaling. Il devrait être unmarshalled en un type concret en tant que struct.

À partir de la structure YAML, il pourrait être traduit comme un type struct comme ceci:

    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)
    }

Et à partir de la structure, il est plus facile d'accéder aux données non modélisées du YAML. Par exemple, si vous souhaitez parcourir l'objet "execute", vous pouvez faire quelque chose comme ceci:

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"`
}

Essayez-le sur le terrain de jeu


0 commentaires