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
3 Réponses :
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 .
Excusez-vous, j'aurais dû être plus clair. J'ai édité la question. Merci.
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)
}
}
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