2017-05-30 1 views
1

J'ai un struct comme celui-ci:utilisant la réflexion SetString

type ProductionInfo struct { 
    StructA []Entry 
} 

type Entry struct { 
    Field1 string 
    Field2 int 
} 

Je voudrais changer la valeur de Field1 utilisant la réflexion, mais l'objet retourné reflètent toujours CanSet() = false. Que puis-je faire? Voir l'exemple de terrain de jeu.

https://play.golang.org/p/eM_KHC3kQ5

Voici le code:

func SetField(source interface{}, fieldName string, fieldValue string) { 
    v := reflect.ValueOf(source) 
    tt := reflect.TypeOf(source) 

    for k := 0; k < tt.NumField(); k++ { 
     fieldValue := reflect.ValueOf(v.Field(k)) 

     fmt.Println(fieldValue.CanSet()) 
     if fieldValue.CanSet() { 
      fieldValue.SetString(fieldValue.String()) 
     } 
    } 
} 

func main() { 
    source := ProductionInfo{} 
    source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2}) 

    SetField(source, "Field1", "NEW_VALUE") 
} 

Répondre

1

erreurs multiples. Passons en revue sur eux.

D'abord, vous passez une valeur de ProductionInfo et non une valeur de Entry dont le champ que vous souhaitez modifier, donc d'abord changer à:

SetField(source.StructA[0], "Field1", "NEW_VALUE") 

Ensuite, vous passez une valeur (non-pointeur) . Vous ne pouvez pas modifier les champs d'une structure sans pointeur avec la réflexion, car cela ne modifierait qu'une copie qui serait rejetée. Afin d'éviter cela (et plus de confusion), cela n'est pas autorisé (CanSet() renvoie false). Donc, vous devez passer un pointeur vers la struct:

SetField(&source.StructA[0], "Field1", "NEW_VALUE") 

maintenant à l'intérieur SetField() le reflect.ValueOf(source) décrira le pointeur passé. Vous pouvez utiliser Value.Elem() pour accéder au reflect.Value de l'objet pointu (la valeur struct):

v := reflect.ValueOf(source).Elem() 

Et maintenant il fonctionne. Code modifié:

func SetField(source interface{}, fieldName string, fieldValue string) { 
    v := reflect.ValueOf(source).Elem() 

    fmt.Println(v.FieldByName(fieldName).CanSet()) 

    if v.FieldByName(fieldName).CanSet() { 
     v.FieldByName(fieldName).SetString(fieldValue) 
    } 
} 

func main() { 
    source := ProductionInfo{} 
    source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2}) 

    fmt.Println("Before: ", source.StructA[0]) 
    SetField(&source.StructA[0], "Field1", "NEW_VALUE") 
    fmt.Println("After: ", source.StructA[0]) 
} 

sortie (essayez le Go Playground):

Before: {A 2} 
true 
After: {NEW_VALUE 2} 
+0

Nous vous remercions de conseils Icza. Je sais qu'il y avait des erreurs lors de l'asssegnation car j'ai essayé de créer du code "fictif" par exemple et je l'ai fait en très peu de temps :). BTW je suis arrivé là où mes erorrs étaient. Je vous remercie – Davide