122 votes

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

avoir un moment difficile de travailler avec struct champs à l'aide d' reflect package. en particulier, n'ont pas compris comment définissez la valeur de champ.

t de type struct { fi int; fs string }
var r t = t{ 123, "jblow" }
var i64 int64 = 456
  1. obtenir le Nom de domaine i - cela semble fonctionner

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

  2. l'obtention de la valeur d'un champ qu'un i) de l'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 de champ i - essayez une panique

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    panique: réfléchir.Valeur·SetInt à l'aide de la valeur obtenue à l'aide de désexporter champ

    en supposant qu'il n'aimait pas les noms des champs "id" et "nom", alors renommé "Id" et "Nom"

    a) cette hypothèse est correcte?

    b) si elle est correcte, pensais pas nécessaire, puisque dans le même fichier / package

  4. réglage de la valeur de champ i - essayer les deux (avec des noms de champ en majuscule ) - panique

    reflect.ValueOf(r).Field(i).SetInt( 465 )

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    panique: réfléchir.Valeur·SetInt à l'aide de unaddressable valeur


Les Instructions ci-dessous par @peterSO sont complets et de haute qualité

Quatre. ceci fonctionne:

reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )

il documents ainsi que les noms des champs doivent être exportable (commencer avec une lettre majuscule)

178voto

peterSO Points 25725

Go est disponible en code source ouvert. Une bonne façon d'apprendre à propos de la réflexion est de voir comment le noyau Aller développeurs de l'utiliser. Par exemple, l'Aller de l'esf et json paquets. La documentation du paquet a des liens vers les fichiers de code source sous la rubrique fichiers de Package.

L'Aller json paquet commissaires et unmarshals JSON à partir et d'Aller structures.


Voici une étape par étape exemple qui définit la valeur d'un struct domaine, tout en évitant les erreurs.

Le Go reflect paquet a un CanAddr fonction.

func (v Value) CanAddr() bool

CanAddr renvoie true si la valeur de l' l'adresse peut être obtenue avec de l'Addr. Ces valeurs sont appelées adressable. Un la valeur est adressable si c'est un élément d'une tranche, d'un élément d'une adressable tableau, un champ d'un adressable struct, ou le résultat de un déréférencement d'un pointeur. Si CanAddr renvoie la valeur false, l'appel sera Addr la panique.

Le Go reflect paquet a un CanSet de la fonction, qui, si true, implique qu' CanAddr également true.

func (v Value) CanSet() bool

CanSet retourne true si la valeur de v peut être changé. Une Valeur peut être changée seulement si il est adressable et n'a pas été obtenue par l'utilisation de désexporter structure des champs. Si CanSet retourne faux, l'appel de Set ou de toute type spécifique de setter (par exemple, SetBool, SetInt64) panique.

Nous devons nous assurer que nous pouvons Set le struct champ. 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 tous les contrôles d'erreur sont inutiles, l'exemple 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)
}

16voto

Asgeir Points 814

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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X