2015-01-16 13 views
6

Ich möchte structs Zeiger übergeben, um die Schnittstelle {} zu erwarten. Dann (durch Reflektion) den Zeiger auf den Member der Struktur holen und ihn dann mit diesem Zeiger modifizieren. Ich habe viel von Q & A gelesen und viel von Variationen versucht, aber immer noch kann ich es funktionieren.Wie bekomme Zeiger von Struktur Mitglied von Schnittstelle {} (Reflexion). Golang

Betrachten wir folgende Beispiel:

type Robot struct { 
    Id int 
} 
f := func(i interface {}) { 
    v := reflect.ValueOf(i).Elem().FieldByName("Id") 
    ptr := v.Addr().Pointer() 
    *ptr = 100 
    //^ it needs to me for functions expecting the pointer: Scan(&pointerToValue) 
} 

robot := &Robot{} 
f(robot) 
println(robot.Id) //I want to get here 100 

ich glaube, das Problem in einem schlechten Verständnis, was Adr tatsächlich tun() und Pointer() Methoden der Verpackung widerspiegeln ..

Antwort

16

Hier ist ein Arbeits Version der Funktion f:

func f(i interface{}) { 
    v := reflect.ValueOf(i).Elem().FieldByName("Id") 
    ptr := v.Addr().Interface().(*int) 
    *ptr = 100 
} 

playground example

Die Umwandlung Zeiger auf ganzzahlige geht wie folgt:

  • v a reflect.Value ist das int Feld darstellt.
  • v.Addr() ist ein relfect.Value einen Zeiger auf das Feld int darstellt.
  • v.Addr().Interface() ist ein interface{} die int Zeiger enthält.
  • v.Addr().Interface().(*int)type asserts die interface{} auf ein *int

Sie das Feld direkt, ohne dabei einen Zeiger einstellen:

func f(i interface{}) { 
    v := reflect.ValueOf(i).Elem().FieldByName("Id") 
    v.SetInt(100) 
} 

playground example

Wenn Sie den Wert entlang zu etwas vorbei erwartet Schnittstelle {} (wie die Methoden db/sql Scan), dann können Sie die Typassertion entfernen:

func f(i interface{}) { 
    v := reflect.ValueOf(i).Elem().FieldByName("Id") 
    scan(v.Addr().Interface()) 
} 

playground example

+1

Big danke. Mein Gehirn ist überlastet, ich versuche es morgen zu überprüfen! Ich denke, ich brauche Zeit und Übung, um wirklich zu verstehen, was hier vor sich geht. Vor allem hier! 'v.Addr(). Interface(). (* int)'. Könnten Sie teilen, wo kann ich diese Art von Wissen erfassen?) –

+2

@TimurFayzrakhmanov Ich aktualisierte die Antwort mit einer Aufschlüsselung des Ausdrucks 'v.Addr(). Interface(). (* Int)'. –

+1

v.Addr(). Interface() funktioniert hervorragend für DB-Aktionen. Vielen Dank dafür! – WhiteAngel

Verwandte Themen