Я работаю над системой шаблонов, написанной на Go, что означает, что она требует либерального использования пакета reflect
. В этом конкретном случае мне нужно иметь возможность динамически вызывать метод на interface{}
. Странность заключается в том, что моя логика отражения работает нормально, пока мои данные имеют известный тип, но не если данные имеют тип interface{}
.
В следующем примере вы можете увидеть, что логика в main()
и Pass()
идентична. Единственное различие заключается в том, являются ли данные известным типом или известным типом внутри interface{}
Go Play: http://play.golang.org/p/FTP3wgc0sZ
package main
import (
"fmt"
"reflect"
)
type Test struct {
Start string
}
func (t *Test) Finish() string {
return t.Start + "finish"
}
func Pass(i interface{}) {
_, ok := reflect.TypeOf(&i).MethodByName("Finish")
if ok {
fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0])
} else {
fmt.Println("Pass() fail")
}
}
func main() {
i := Test{Start: "start"}
Pass(i)
_, ok := reflect.TypeOf(&i).MethodByName("Finish")
if ok {
fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0])
} else {
fmt.Println("main() fail")
}
}
После выполнения этого кода мы получим следующий результат:
Pass() fail
startfinish
Это означает, что моя методология динамического вызова метода работает отлично, за исключением сценария, когда мой объект в настоящее время находится в interface{}
.
Если вместо этого я не использую приемник указателей и не передаю i
, тогда он работает как ожидалось.
Go Play: http://play.golang.org/p/myM0UXVYzX
Это заставляет меня думать, что моя проблема в том, что я не могу получить адрес я (&i
), когда он является interface{}
. Я просмотрел пакет отражения и протестировал такие вещи, как reflect.Value.Addr()
и reflect.PtrTo()
, но я не мог работать так, как мне было нужно. Моя догадка заключается в том, что она имеет какое-то отношение к тому, что interface{}
по определению является ссылочным объектом.