2013-09-21 4 views
38

Ecco un semplice programma di andare che non funziona:GoLang: Accesso struct proprietà per nome

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: invalid operation: v[property] (index of type *Vertex)

Quello che voglio è quello di accedere alla proprietà Vertex X utilizzando il suo nome. Se faccio v.X funziona, ma non lo fa v["X"].

Qualcuno può dirmi come farlo funzionare?

risposta

56

La maggior parte del codice non dovrebbe richiedere questo tipo di ricerca dinamica. È inefficiente rispetto all'accesso diretto (il compilatore conosce l'offset del campo X in una struttura Vertex, può compilare v.X in una singola istruzione macchina, mentre una ricerca dinamica 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 ... il linguaggio fornisce un modulo reflect per le rare volte in cui è necessario.

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 c'è nessun controllo degli errori qui, quindi si otterrà un panico se chiedete un campo che non esiste, o il campo non è di tipo int. Controlla the documentation for reflect per maggiori dettagli.

+2

+1, e vedere anche [Le leggi di riflessione] (http://blog.golang.org/laws-of-reflection) che fornisce un'introduzione all'idea. –

+1

Questo modulo di riflessione è un po 'complicato. Ho provato a usarlo senza successo. Sembra che mi stia dimenticando di chiamare "Ìindiretto". Grazie per l'esempio di lavoro e tutte le spiegazioni. Apprezzo davvero :-) –

+1

Grazie per la spiegazione sopra il codice. Per me è ancora più utile del codice stesso! – Nebulosar

6

Yuo ora ha il progetto oleiade/reflections che consente di ottenere/impostare campi sul valore della struttura o puntatori.
Rende meno semplice l'uso di reflect package.

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