web-dev-qa-db-fra.com

En utilisant reflect, comment définissez-vous la valeur d'un champ struct?

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 
  1. obtenir le nom du champ i - cela semble fonctionner

    var field = reflect.TypeOf(r).Field(i).Name

  2. 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())

  3. 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

  4. 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)

87
cc young

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

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
11
Asgeir