2015-01-16 15 views
6

Chcę przekazać struct's wskaźnik do funkcji, które oczekują interfejsu {}. Następnie przenieś (przez odbicie) wskaźnik na element struktury, a następnie zmodyfikuj go za pomocą tego wskaźnika. Dużo czytałem w Q & A i wypróbowałem wiele wariantów, ale wciąż mogę to zrobić.Jak uzyskać wskaźnik elementu struct z interfejsu {} (odbicie). Golang

Rozważmy przykład poniżej:

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 

Myślę, że problem w złym zrozumieniu co faktycznie Addr() i Pointer() metody odzwierciedlają pakiet ..

Odpowiedz

16

Oto robocza wersja funkcji f:

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

playground example

Konwersja do liczby całkowitej wskaźnik idzie w następujący sposób:

  • v jest reflect.Value reprezentujący pole int.
  • v.Addr() to relfect.Value reprezentujący wskaźnik do pola int.
  • v.Addr().Interface() to interface{} zawierający wskaźnik int.
  • v.Addr().Interface().(*int)type assertsinterface{} Do *int

Można ustawić pole bezpośrednio bez uzyskania wskaźnika:

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

playground example

Jeśli przechodzącej wartość wzdłuż czegoś spodziewa interfejsu {} (podobnie jak metody db/sql Scan), następnie można usunąć asercję typu:

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

playground example

+1

Big dziękuję. Mój mózg jest przeciążony, próbuję to sprawdzić jutro! Myślę, że potrzebuję czasu i praktyki, żeby naprawdę zrozumieć, co tu się dzieje. Zwłaszcza tutaj! 'v.Addr(). Interfejs(). (* int)'. Czy mógłbyś podzielić się tym, gdzie mogę zdobyć tego rodzaju wiedzę?) –

+2

@TimurFayzrakhmanov I zaktualizowałem odpowiedź z podziałem wyrażenia "v.Addr(). Interface(). (* Int)'. –

+1

v.Addr(). Interfejs() działa doskonale dla działań DB. Bardzo ci za to dziękuję! – WhiteAngel

Powiązane problemy