Mam funkcję, która iteruje przez wszystkie pola interfejsu przekazane jako parametr. Aby to osiągnąć, używam refleksji. Problem polega na tym, że nie wiem, jak uzyskać adres pola bez wskaźnika. Oto przykład:Uzyskaj wskaźnik do wartości za pomocą refleksji
type Z struct {
Id int
}
type V struct {
Id int
F Z
}
type T struct {
Id int
F V
}
Powyższy kod reprezentuje moje struktury testowe. Teraz tutaj jest rzeczywista funkcja, która przemierza określoną strukturę i wymienia dane o nim:
func InspectStruct(o interface{}) {
val := reflect.ValueOf(o)
if val.Kind() == reflect.Interface && !val.IsNil() {
elm := val.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
val = elm
}
}
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
address := "not-addressable"
if valueField.Kind() == reflect.Interface && !valueField.IsNil() {
elm := valueField.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
valueField = elm
}
}
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
address = fmt.Sprint(valueField.Addr().Pointer())
}
fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\t, Field type: %v\t, Field kind: %v\n", typeField.Name,
valueField.Interface(), address, typeField.Type, valueField.Kind())
if valueField.Kind() == reflect.Struct {
InspectStruct(valueField.Interface())
}
}
}
I tu jest rzeczywista próba po struktura konkretyzacji/inicjalizacji:
t := new(T)
t.Id = 1
t.F = *new(V)
t.F.Id = 2
t.F.F = *new(Z)
t.F.F.Id = 3
InspectStruct(t)
I wreszcie wyjście InspectStruct rozmowy :
Field Name: Id, Field Value: 1, Address: 408125440 , Field type: int , Field kind: int
Field Name: F, Field Value: {2 {3}}, Address: 408125444 , Field type: main.V , Field kind: struct
Field Name: Id, Field Value: 2, Address: not-addressable , Field type: int , Field kind: int
Field Name: F, Field Value: {3}, Address: not-addressable , Field type: main.Z , Field kind: struct
Field Name: Id, Field Value: 3, Address: not-addressable , Field type: int , Field kind: int
Jak widać Używam rekursji, więc jeśli jedno z pól jest struct rodzaj potem zadzwonię InspectStruct dla niego. Mój problem polega na tym, że chociaż wszystkie pola zostały zainicjowane dla całej hierarchii "t" struktury, nie jestem w stanie uzyskać adresu dla dowolnego pola położonego na większej głębokości niż "t". Naprawdę doceniłbym każdą pomoc.
dowiedziałem się od tego, dzięki za szczegółową odpowiedź. – OneOfOne
Dzięki za uzupełnienie odpowiedzi @OneOfOne. Bardzo doceniane! –