繁体   English   中英

将字段名称反映到特定界面

[英]Go Reflect field name to specific interface

我有一个带有许多字段的struct类型,这些字段都实现了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方法,则它始终为false,因此实际上似乎没有答案问题。

似乎Addr是关键,因为它专门提到了指针接收器,但是我正在努力将其强制返回接口。

使用此代码:

func renderField(name string, f *First) {
    structVal := reflect.ValueOf(f).Elem()
    field := structVal.FieldByName(name).Addr().Interface()
    if renderer, ok := field.(Renderer); ok {
        renderer.Render()
    }
}

关键是要更改:

structVal := reflect.ValueOf(*f)

至:

structVal := reflect.ValueOf(f).Elem()

问题中使用的语句创建了一个不可寻址的结构值。 不可寻址结构中的字段也是不可寻址的,因此无法访问这些字段上的指针接收器。

此答案中使用的语句创建一个可寻址的结构值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM