2013-09-21 15 views
38

Oto prosty program, który Go nie działa:GoLang: dostęp struct nieruchomość wg nazwy

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] 
} 

Błąd: prog.go:18: invalid operation: v[property] (index of type *Vertex)

Co chcę jest dostęp do własności Vertex X używając jego imienia. Jeśli wykonam v.X, to działa, ale nie działa.

Czy ktoś może mi powiedzieć, jak to zrobić?

Odpowiedz

56

Większość kodu nie powinna wymagać tego rodzaju dynamicznego wyszukiwania. Jest nieefektywny w porównaniu do bezpośredniego dostępu (kompilator zna przesunięcie pola X w strukturze Vertex, może skompilować v.X do pojedynczej instrukcji maszyny, podczas gdy dynamiczne wyszukiwanie będzie wymagało pewnego rodzaju implementacji tablic mieszających lub podobnych). Hamuje również pisanie statyczne: kompilator nie ma możliwości sprawdzenia, czy nie próbujesz uzyskać dostępu do nieznanych pól dynamicznie, i nie może wiedzieć, jaki powinien być wynikowy typ.

Ale ... język zapewnia moduł reflect w rzadkich przypadkach, gdy jest to potrzebne.

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()) 
} 

Nie ma tutaj sprawdzania błędów, więc dostaniesz panikę, jeśli poprosić o dziedzinie, która nie istnieje, czy pole nie jest typu int. Aby uzyskać więcej informacji, sprawdź numer the documentation for reflect.

+2

+1, patrz także [The Laws of Reflection] (http://blog.golang.org/laws-of-reflection), który stanowi wprowadzenie do idei. –

+1

Ten moduł odbijający jest trochę skomplikowany. Próbowałem go użyć bez powodzenia. Wygląda na to, że zapomniałem nazywać 'Ìndirect'. Dzięki za działający przykład i wszystkie wyjaśnienia. Naprawdę doceniam :-) –

+1

Dzięki za wyjaśnienie powyżej kodu. Dla mnie jest to nawet bardziej przydatne niż sam kod! – Nebulosar

6

Yuo ma teraz projekt oleiade/reflections, który pozwala uzyskać/ustawić pola na wartości struct lub wskaźniki.
To sprawia, że ​​korzystanie z reflect package jest mniej skomplikowane.

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 
Powiązane problemy