使用反射迭代struct的struct成员并在其上调用方法

时间:2018-03-07 22:40:35

标签: go methods struct reflection interface

我有一个x[, as.vector(!is.na(colSums(x))) | grepl(pattern = "name", names(x))] # age_1 age_3 name_1 name_2 #1 0 1 NA NA #2 1 0 NA NA #3 1 0 NA NA #4 0 0 NA NA ,其中包含一个或多个struct个成员。每个成员都应实现struct接口。

我想使用反射来迭代所有Validator成员并调用界面的struct方法。例如:

Validate()

运行时,输出:

  

恐慌:界面转换:main.T1不是main.Validator:缺少方法验证

如果我将package main import "fmt" import "reflect" type Validator interface { Validate() } type T1 struct { S string } func (p *T1) Validate() { fmt.Println("HERE 1") } type T2 struct { S string } func (p *T2) Validate() { fmt.Println("HERE 2") } type Top struct { S1 T1 S2 T2 } func main() { var t Top r := reflect.ValueOf(t) for i := 0; i < r.NumField(); i++ { f := r.Field(i) if f.Kind() == reflect.Struct { validator := f.Interface().(Validator) validator.Validate() } } } 方法更改为接受值(而不是指针)接收器,那么它可以工作。但是,我希望使用指针接收器,因为Validate()可能会变大。

如何更改反射代码以使用指针接收器定义方法?

我也尝试过这一行:

struct

获取指针,但然后输出:

  

panic:reflect.Value.Addr,无法取消值

2 个答案:

答案 0 :(得分:2)

您的所有值都不可寻址,因此您无法通过指针接收器调用它们上的任何方法。

如果S1S2字段不能成为指针,那么如果您有指向Top结构的指针,您仍然可以解决这些问题:

r := reflect.ValueOf(&t).Elem()
for i := 0; i < r.NumField(); i++ {
    f := r.Field(i)
    if f.Kind() == reflect.Struct {
        validator := f.Addr().Interface().(Validator)
        validator.Validate()
    }
}

答案 1 :(得分:1)

&#34; Top.S1&#34;属于&#34; T1&#34;与&#34; * T1&#34;不同类型定义&#34;验证()&#34;。

如果你改变&#34; Top.S1&#34;到&#34; * T1&#34;键入并修改字段类型检查,您的代码将正常工作。

type Top struct {
    S1 *T1
    S2 *T2
}

func main() {
    t := Top{&T1{}, &T2{}}

    r := reflect.ValueOf(t)
    for i := 0; i < r.NumField(); i++ {
        f := r.Field(i)
        if f.Kind() == reflect.Ptr && f.Elem().Kind() == reflect.Struct {
            validator, ok := f.Interface().(Validator)
            if ok {
                validator.Validate()
            } else {
                fmt.Println("not ok")
            }
        }
    }
}

https://play.golang.org/p/hHqP6WdMYqT