J'ai donc trouvé du code qui m'aide à démarrer la réflexion dans Go (golang), mais j'ai du mal à obtenir une valeur sous-jacente pour pouvoir créer un map[string]string
à partir d'une structure et de ses champs.
Finalement, je voudrais faire du résultat un map[string]interface{}
, mais ce seul problème me bloque en quelque sorte.
Le code que j'ai en ce moment:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
FirstName string `tag_name:"tag 1"`
LastName string `tag_name:"tag 2"`
Age int `tag_name:"tag 3"`
}
func inspect(f interface{}) map[string]string {
m := make(map[string]string)
val := reflect.ValueOf(f).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
f := valueField.Interface()
val := reflect.ValueOf(f)
m[typeField.Name] = val.String()
}
return m
}
func dump(m map[string]string) {
for k, v := range m {
fmt.Printf("%s : %s\n", k, v)
}
}
func main() {
f := &Foo{
FirstName: "Drew",
LastName: "Olson",
Age: 30,
}
a := inspect(f)
dump(a)
}
Le résultat de l'exécution du code:
FirstName : Drew
LastName : Olson
Age : <int Value>
D'après ce que je comprends, la sortie pour FirstName et LastName sont des objets reflet.Value réels, mais pour les chaînes, la méthode String () sur la valeur ne produit que la chaîne sous-jacente. J'aimerais obtenir l'int et le changer en une chaîne, mais à partir de la documentation du paquet relect, je ne vois pas immédiatement comment cela se fait.
Soo .... Comment puis-je obtenir la valeur sous-jacente d'un reflet.Value dans golang?
Un bon exemple de la façon d'analyser les valeurs est le package fmt
. Voir ce code .
L'utilisation du code mentionné pour correspondre à votre problème ressemblerait à ceci:
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
m[typeField.Name] = strconv.FormatInt(val.Int(), 10)
case reflect.String:
m[typeField.Name] = val.String()
// etc...
}
Fondamentalement, vous devez vérifier tous types disponibles .
Il semble que vous soyez sur la bonne voie. Le problème que je vois avec votre code est qu'il fait des hypothèses sur les valeurs, ce qui signifie quand appelez-vous Elem()
et combien de fois (pour résoudre les pointeurs). Pour le savoir, vous devez regarder le reflect.Kind
. La valeur est-elle un reflect.Ptr
? Utilisez ensuite Elem()
.
Une fois que vous avez la valeur de val.Interface()
/val.String()
/val.Int()
, vous pouvez convertir vos valeurs selon vos besoins. Ce que vous utiliserez dépendra de reflect.Kind
. Pour convertir un int
vers/depuis string
, vous devez utiliser le package strconv
.
Les packages encoding/json
Et encoding/xml
Font déjà ce genre de travail. Le code source fournit de bons exemples. Par exemple, jetez un œil à copyValue
in encoding/xml/read.go et marshalSimple
in encoding/xml/marshal.go .
Cela devrait être plus facile à faire avec Go 1.5 (août 2015) Voir revue 8731 et commit 049b89d par Rob Pike (robpike
) =:
fmt
: traitereflect.Value
spécialement - comme la valeur qu'il contient
Cela vous permettrait d'imprimer la valeur réelle d'un argument Reflect.Value()
:
Lorsqu'un
reflect.Value
Est passé àPrintf
(etc.),fmt
appelle la méthodeString
, qui ne divulgue pas son contenu.
Pour obtenir le contenu, on pourrait appelerValue.Interface()
, mais c'est illégal si leValue
n'est pas exporté ou autrement interdit.Ce CL améliore la situation avec une modification triviale du package
fmt
: lorsque nous voyons unreflect.Value
Comme argument, nous le traitons exactement comme nous traitons unreflect.Value
Que nous faisons à l'intérieur le paquet.
Cela signifie que nous imprimons toujours le contenu deValue
comme si qui était l'argument dePrintf
.C'est sans doute un changement de rupture, mais je pense que c'est une véritable amélioration et pas plus de rupture que de nombreux autres ajustements que nous avons apportés à la sortie formatée de ce package.