У меня есть тип структуры с несколькими полями, которые все реализуют интерфейс Renderer. Типы полей реализуют интерфейс с указателями получателей. Я хотел бы иметь функцию, которая принимает имя поля и вызывает метод Render для этого поля. Я могу найти поле и получить много информации о нем, но выполнение утверждения типа, кажется, кусает меня из-за получателей указателя. Вот код, который показывает мою проблему:
package main
import (
"fmt"
"reflect"
)
type Renderer interface {
Render()
}
type First struct {
ExampleField Field
}
type Field []int
func (f *Field) Render() {
fmt.Println("Hello from first")
}
func main() {
f := First{
Field{1, 2, 3},
}
f.ExampleField.Render()
renderField("ExampleField", &f)
renderField2("ExampleField", &f)
}
func renderField(field string, f *First) {
structVal := reflect.ValueOf(*f)
renderType := reflect.TypeOf((*Renderer)(nil)).Elem()
fieldToRender := structVal.FieldByName(field)
fieldPtr := reflect.PtrTo(fieldToRender.Type())
fmt.Printf("Implements? %v\n", fieldPtr.Implements(renderType))
fmt.Printf("Addressable? %v\n", fieldToRender.CanAddr())
fieldInter := fieldToRender.Interface()
if renderer, ok := fieldInter.(Renderer); ok {
// Pointer receiver so this never gets called
fmt.Print("Able to cast")
renderer.Render()
}
}
func renderField2(field string, f *First) {
structVal := reflect.ValueOf(*f)
fieldToRender := structVal.FieldByName(field)
vp := reflect.New(reflect.TypeOf(fieldToRender))
vp.Elem().Set(reflect.ValueOf(fieldToRender))
vpAddr := vp.Elem().Addr()
typeVal := vpAddr.Interface()
fmt.Println(typeVal) // <main.Field Value>⏎
renderer := typeVal.(Renderer)
renderer.Render()
// interface conversion: *reflect.Value is not main.Renderer: missing method Render
}
renderField2, кажется, приближает меня, но Addr () дает мне * Reflect.Value, и когда я вызываю Interface (), вместо этого представляется базовый тип. Если я переключаюсь на приемник без указателя, то первая функция работает. Я обнаружил, что отражает значение Интерфейс и указатель приемника , который, кажется, почти точно соответствует тому, что я спрашиваю, и на вопрос дан ответ, но если я на самом деле вызываю метод isZeroer, представленный в ссылке для игровой площадки, он всегда ложен, поэтому он не кажется, на самом деле не отвечает на вопрос.
Кажется, что Addr является ключом, потому что в нем конкретно упоминаются приемники указателей, но я изо всех сил пытаюсь вернуть его обратно в интерфейс.