web-dev-qa-db-fra.com

Itérer à travers les champs d'une structure dans Go

Fondamentalement, le seul moyen (que je sache) de parcourir les valeurs des champs d'un struct est comme suit:

type Example struct {
    a_number uint32
    a_string string
}

//...

r := &Example{(2 << 31) - 1, "...."}:
for _, d:= range []interface{}{ r.a_number, r.a_string, } {
  //do something with the d
}

Je me demandais s'il existait un moyen plus performant et plus polyvalent de réaliser []interface{}{ r.a_number, r.a_string, }. Je n'ai donc pas besoin de répertorier chaque paramètre individuellement. Sinon, existe-t-il un meilleur moyen de parcourir une structure?

J'ai essayé de regarder à travers le paquet reflect , mais je me suis heurté à un mur, car je ne sais pas quoi faire une fois que j'ai récupéré reflect.ValueOf(*r).Field(0).

Merci!

76
omninonsense

Une fois que vous avez récupéré le reflect.Value Du champ en utilisant Field(i), vous pouvez en obtenir une valeur d'interface en appelant Interface(). Ladite valeur d'interface représente alors la valeur du champ.

Il n’existe aucune fonction permettant de convertir la valeur du champ en un type concret, car, comme vous le savez peut-être, aucun médicament générique n’est utilisé. Ainsi, il n'y a pas de fonction avec la signature GetValue() T avec T étant le type de ce champ (qui change bien sûr, en fonction du champ).

Le plus proche que vous puissiez obtenir au rendez-vous est GetValue() interface{} et c’est exactement ce que propose reflect.Value.Interface().

Le code suivant montre comment obtenir les valeurs de chaque champ exporté dans une structure en utilisant une réflexion ( play ):

import (
    "fmt"
    "reflect"
)

func main() {
    x := struct{Foo string; Bar int }{"foo", 2}

    v := reflect.ValueOf(x)

    values := make([]interface{}, v.NumField())

    for i := 0; i < v.NumField(); i++ {
        values[i] = v.Field(i).Interface()
    }

    fmt.Println(values)
}
92
nemo

Si vous voulez parcourir les champs et les valeurs d'une structure, vous pouvez utiliser le code Go ci-dessous comme référence.

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Fname  string
    Lname  string
    City   string
    Mobile int64
}

func main() {
    s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
    v := reflect.ValueOf(s)
    typeOfS := v.Type()

    for i := 0; i< v.NumField(); i++ {
        fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
    }
}

Run in playground

Remarque: Si les champs de votre structure ne sont pas exportés, la v.Field(i).Interface() donnera la panique panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.

0
chetan kumar