2017-10-21 55 views
2

J'ai un struct qui ressemble à ceci:Append à un champ de tranche dans une struct utilisant la réflexion

type guitaristT struct { 
    Surname string `required=true` 
    Year  int64 `required=false` 
    American bool  // example of missing tag 
    Rating float32 `required=true` 
    Styles []string `required=true,minsize=1` 
} 

J'ai une variable d'environnement qui ressemble à ce qui suit, et j'utilise la réflexion pour remplir le struct basé sur les touches.

jimiEnvvar :="surname=Hendrix|year=1942|american=true|rating=9.99 
    |styles=blues|styles=rock|styles=psychedelic" 

Je suis en mesure de définir les champs à l'aide string, int64, bool and float32 la réflexion, mais je suis coincé sur la façon d'ajouter au champ sliceStyles. Par exemple, basé sur le jimiEnvvar ci-dessus je voudrais que le champ jimi.Styles ait les valeurs ["blues","rock", "psychedelic"].

Je le suivant (simplifié) code:

result := guitaristT{} 
// result.Styles = make([]string, 10) // XXX causes 10 empty strings at start 
result.Styles = make([]string, 0)  // EDIT: Alessandro's solution 
... 
v := reflect.ValueOf(&result).Elem() 
... 
field := v.FieldByName(key) // eg key = "styles" 
... 
switch field.Kind() { 

case reflect.Slice: 
    // this is where I get stuck 
    // 
    // reflect.Append() has signature: 
    // func Append(s Value, x ...Value) Value 

    // so I convert my value to a reflect.Value 
    stringValue := reflect.ValueOf(value) // eg value = "blues" 

    // field = reflect.Append(field, stringValue) // XXX doesn't append 
    field.Set(reflect.Append(field, stringValue)) // EDIT: Alessandro's solution 

EDIT:

une seconde partie (dont je résolu) a été le remplissage d'une carte dans le struct. Par exemple:

type guitaristT struct { 
    ... 
    Styles []string `required=true,minsize=1` 
    Cities map[string]int 
} 

Où jimiEnvvar ressemble:

jimiEnvvar += "|cities=New York^17|cities=Los Angeles^14" 

je l'ai écrit de cette manière:

case reflect.Map: 
     fmt.Println("keyAsString", keyAsString, "is Map, has value:", valueAsString) 
     mapKV := strings.Split(valueAsString, "^") 
     if len(mapKV) != 2 { 
      log.Fatalln("malformed map key/value:", mapKV) 
     } 
     mapK := mapKV[0] 
     mapV := mapKV[1] 
     thisMap := fieldAsValue.Interface().(map[string]int) 
     thisMap[mapK] = atoi(mapV) 
     thisMapAsValue := reflect.ValueOf(thisMap) 
     fieldAsValue.Set(thisMapAsValue) 

The final result was: 

main.guitaristT{ 
    Surname: "Hendrix", 
    Year:  1942, 
    American: true, 
    Rating: 9.989999771118164, 
    Styles: {"blues", "rock", "psychedelic"}, 
    Cities: {"London":11, "Bay Area":9, "New York":17, "Los Angeles":14}, 
} 

Si vous êtes intéressé, le code complet est à https://github.com/soniah/reflect/blob/master/structs.go. Le code est juste quelques notes/exercices que j'écris.


EDIT2:

Chapitre 11 "Allez dans la pratique" (Butcher et Farina) a des explications détaillées de la réflexion, struct et tags.

Répondre

1

Vous n'étiez pas trop loin. Il suffit de remplacer par

field.Set(reflect.Append(field, stringValue)) 

et vous avez terminé. Aussi, assurez-vous que vous initialisez la tranche en utilisant

result.Styles = make([]string, 0) 

ou vous finirez par avoir 10 chaîne vide en haut du tableau Styles.

J'espère que cela aidera et bonne chance avec votre projet.

+0

Merci pour votre réponse Alessandro. Aujourd'hui, j'ai travaillé sur le code de la carte, que j'ai ajouté ci-dessus. Cela fonctionne, mais peut-être avez-vous des commentaires sur l'amélioration? –