avoir du mal à travailler avec des champs struct en utilisant le package reflect
. en particulier, n'ont pas compris comment définir la valeur du champ.
type t struct {fi int; fs string} varr t = t {123, "jblow"} var i64 int64 = 456
obtenir le nom du champ i - cela semble fonctionner
var field = reflect.TypeOf(r).Field(i).Name
obtenir la valeur du champ i comme a) interface {}, b) int - cela semble fonctionner
var iface interface{} = reflect.ValueOf(r).Field(i).Interface()
var i int = int(reflect.ValueOf(r).Field(i).Int())
réglage de la valeur du champ i - essayez-en un - panique
reflect.ValueOf(r).Field(i).SetInt( i64 )
panique: reflect.Value · SetInt utilisant une valeur obtenue avec un champ non exporté
en supposant qu'il n'aimait pas les noms de champs "id" et "name", ainsi renommé "Id" et "Name"
a) cette hypothèse est-elle correcte?
b) si correct, jugé inutile car dans le même fichier/package
réglage de la valeur du champ i - essayez-en deux (avec les noms de champs en majuscule) - panique
reflect.ValueOf(r).Field(i).SetInt( 465 )
reflect.ValueOf(r).Field(i).SetInt( i64 )
panique: reflect.Value · SetInt utilisant une valeur non adressable
Les instructions ci-dessous de @peterSO sont complètes et de grande qualité.
Quatre. cela marche:
reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )
il documente également que les noms de champs doivent être exportables (commencent par une lettre majuscule)
Go est disponible en tant que code source ouvert . Un bon moyen d’en apprendre davantage sur la réflexion est de voir comment les développeurs Go principaux l’utilisent. Par exemple, les packages Go fmt et json . La documentation du package contient des liens vers les fichiers de code source sous l'en-tête Fichiers de package.
Le paquet Go json marshals et JSON unmarshals de et vers les structures Go.
Voici un exemple pas à pas qui définit la valeur d'un champ struct
tout en évitant soigneusement les erreurs.
Le paquet Go reflect
a une fonction CanAddr
.
func (v Value) CanAddr() bool
CanAddr renvoie true si l'adresse de la valeur peut être obtenue avec Addr. Ces valeurs sont appelées adressables. Une valeur est adressable s’il s’agit d’un élément d’une tranche, d’un élément d’un tableau adressable, d’un champ d’une structure adressable ou du résultat du déréférencement d’un pointeur. Si CanAddr renvoie False, appeler Addr paniquera.
Le paquet Go reflect
a une fonction CanSet
, qui, si true
, implique que CanAddr
est aussi true
.
func (v Value) CanSet() bool
CanSet renvoie true si la valeur de v peut être modifiée. Une valeur ne peut être modifiée que si elle est adressable et n'a pas été obtenue par l'utilisation de champs struct non exportés. Si CanSet renvoie false, l'appel de Set ou de tout setter spécifique au type (par exemple, SetBool, SetInt64) panique.
Nous devons nous assurer que nous pouvons Set
le champ struct
. Par exemple,
package main
import (
"fmt"
"reflect"
)
func main() {
type t struct {
N int
}
var n = t{42}
// N at start
fmt.Println(n.N)
// pointer to struct - addressable
ps := reflect.ValueOf(&n)
// struct
s := ps.Elem()
if s.Kind() == reflect.Struct {
// exported field
f := s.FieldByName("N")
if f.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if f.CanSet() {
// change value of N
if f.Kind() == reflect.Int {
x := int64(7)
if !f.OverflowInt(x) {
f.SetInt(x)
}
}
}
}
}
// N at end
fmt.Println(n.N)
}
Output:
42
7
Si nous pouvons être certains que toutes les vérifications d'erreur sont inutiles, l'exemple se simplifie,
package main
import (
"fmt"
"reflect"
)
func main() {
type t struct {
N int
}
var n = t{42}
fmt.Println(n.N)
reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
fmt.Println(n.N)
}
Cela semble fonctionner:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Number int
Text string
}
func main() {
foo := Foo{123, "Hello"}
fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
reflect.ValueOf(&foo).Elem().Field(0).SetInt(321)
fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
}
Impressions:
123
321