Wertadresse mithilfe von Reflexion abrufen
Die Reflexion über eine Schnittstelle ermöglicht es einem, deren Felder zu durchqueren. Allerdings stellt das Ermitteln der Adresse eines Nicht-Zeigerfelds eine Herausforderung dar. Dieser Artikel befasst sich mit diesem Problem, indem er die Einschränkungen der Zeiger-Dereferenzierung untersucht und eine Lösung vorstellt.
Problemübersicht
Bedenken Sie den folgenden Code:
<code class="go">type Z struct { Id int } type V struct { Id int F Z } type T struct { Id int F V }</code>
Die Funktion InspectStruct durchläuft rekursiv eine Struktur und listet ihre Felddetails, einschließlich der Adresse, auf. Hier ist eine vereinfachte Implementierung:
<code class="go">func InspectStruct(o interface{}) { val := reflect.ValueOf(o) if val.Kind() == reflect.Interface && !val.IsNil() { val = val.Elem() } if val.Kind() == reflect.Ptr { val = val.Elem() } for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) if valueField.Kind() == reflect.Ptr { valueField = valueField.Elem() } address := "not-addressable" if valueField.CanAddr() { address = fmt.Sprint(valueField.Addr().Pointer()) } fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\n", val.Type().Field(i).Name, valueField.Interface(), address) if valueField.Kind() == reflect.Struct { InspectStruct(valueField.Interface()) } } }</code>
Das Ausführen dieser Funktion auf einer Instanz vom Typ T ergibt:
Field Name: Id, Field Value: 1, Address: 408125440 Field Name: F, Field Value: {2 {3}}, Address: 408125444 Field Name: Id, Field Value: 2, Address: not-addressable Field Name: F, Field Value: {3}, Address: not-addressable Field Name: Id, Field Value: 3, Address: not-addressable
Wie Sie sehen können, sind die Adressen von Nicht-Zeigerfeldern („Id“) und „F“ vom Typ „Z“ und „V“) sind nicht zugänglich.
Lösung
Das Problem ergibt sich aus der Dereferenzierung des von valueField.Interface( ). Dies gibt eine Schnittstelle{} zurück, die bei Verwendung in einem Feldwert zum Verlust der Adressinformationen führen kann.
Hier ist eine modifizierte Lösung, die dieses Problem behebt:
<code class="go">func InspectStructV(val reflect.Value) { if val.Kind() == reflect.Interface && !val.IsNil() { val = val.Elem() } if val.Kind() == reflect.Ptr { val = val.Elem() } for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) if valueField.Kind() == reflect.Ptr { valueField = valueField.Elem() } address := "not-addressable" if valueField.CanAddr() { address = fmt.Sprintf("0x%X", valueField.Addr().Pointer()) } fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\n", val.Type().Field(i).Name, valueField.Interface(), address) if valueField.Kind() == reflect.Struct { InspectStructV(valueField) } } } func InspectStruct(v interface{}) { InspectStructV(reflect.ValueOf(v)) }</code>
Durch Übergabe eines Reflekts .Value anstelle einer Schnittstelle{} zu InspectStructV, die Adresse des Feldes kann korrekt abgerufen werden.
Schlussfolgerung
Beim Durchlaufen von Nicht-Zeigerfeldern in einer Struktur mit Bei der Reflexion ist es wichtig, den „reflect.Value“ beizubehalten, anstatt sich auf „valueField.Interface()“ zu verlassen. Durch die Übergabe von „reflect.Value“ an die rekursive InspectStructV-Funktion können Sie die Adressen von Feldern in jeder Tiefe der Struktur erfolgreich abrufen.
Das obige ist der detaillierte Inhalt vonWie rufe ich die Wertadresse von Nicht-Zeigerfeldern mithilfe von Reflection in Go ab?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!