Accedere alla proprietà struct per nome

Ecco un semplice programma go che non funziona:

package main import "fmt" type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} fmt.Println(getProperty(&v, "X")) } func getProperty(v *Vertex, property string) (string) { return v[property] } 

Errore:

prog.go: 18: operazione non valida: v [proprietà] (indice di tipo * Vertex)

Quello che voglio è accedere alla proprietà di Vertex X usando il suo nome. Se faccio vX funziona, ma v["X"] no.

Qualcuno può dirmi come farlo funzionare?

La maggior parte del codice non dovrebbe richiedere questo tipo di ricerca dynamic. È inefficiente rispetto all’accesso diretto (il compilatore conosce l’offset del campo X in una struttura Vertex, può compilare vX su una singola istruzione macchina, mentre una ricerca dynamic avrà bisogno di una sorta di implementazione della tabella hash o simile). Inoltre, inibisce la tipizzazione statica: il compilatore non ha modo di verificare che non si stia tentando di accedere ai campi sconosciuti in modo dinamico e non può sapere quale dovrebbe essere il tipo risultante.

Ma … la lingua fornisce un modulo di riflessione per le rare volte in cui ne hai bisogno.

 package main import "fmt" import "reflect" type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} fmt.Println(getField(&v, "X")) } func getField(v *Vertex, field string) int { r := reflect.ValueOf(v) f := reflect.Indirect(r).FieldByName(field) return int(f.Int()) } 

Non ci sono errori di controllo qui, quindi ti verrà il panico se chiederai un campo che non esiste, o il campo non è di tipo int. Controlla la documentazione per riflettere per maggiori dettagli.

Ora hai il progetto oleiade / reflections che ti permette di ottenere / impostare campi sul valore della struttura o sui puntatori.
Rende l’uso del pacchetto di reflect meno complicato.

 s := MyStruct { FirstField: "first value", SecondField: 2, ThirdField: "third value", } fieldsToExtract := []string{"FirstField", "ThirdField"} for _, fieldName := range fieldsToExtract { value, err := reflections.GetField(s, fieldName) DoWhatEverWithThatValue(value) } // In order to be able to set the structure's values, // a pointer to it has to be passed to it. _ := reflections.SetField(&s, "FirstField", "new value") // If you try to set a field's value using the wrong type, // an error will be returned err := reflection.SetField(&s, "FirstField", 123) // err != nil