简体   繁体   English

使用反射来遍历struct的struct成员并在其上调用方法

[英]Using reflection to iterate over struct's struct members and calling a method on it

I have a struct that has one or more struct members. 我有一个struct具有一个或多个struct的成员。 Each member is expected to implement a Validator interface. 每个成员Validator实现一个Validator接口。

I want to use reflection to iterate over all struct members and call the interface's Validate() method. 我想使用反射遍历所有struct成员并调用接口的Validate()方法。 For example: 例如:

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()
        }
    }
}

When run, it outputs: 运行时,它输出:

panic: interface conversion: main.T1 is not main.Validator: missing method Validate 紧急:接口转换:main.T1不是main.Validator:缺少方法Validate

If I change the Validate() methods to accept value (rather than pointer) receivers, then it works. 如果我将Validate()方法更改为接受值(而不是指针)接收器,则它将起作用。 However, I want to use pointer receivers since the struct s may grow to be large. 但是,由于struct可能会变大,因此我使用指针接收器。

How can I change the reflection code to work where the methods are defined taking pointer receivers? 如何在使用指针接收器定义方法的地方更改反射代码?

I also tried using this line: 我也尝试使用此行:

            validator := f.Addr().Interface().(Validator)

to get a pointer, but it then outputs: 得到一个指针,但是它输出:

panic: reflect.Value.Addr of unaddressable value 恐慌:无法确定值的reflect.Value.Addr

None of your values are addressable, so you can't call any methods on them with pointer receivers. 您的值都不是可寻址的,因此您不能使用指针接收器在它们上调用任何方法。

If the S1 and S2 fields can't be pointers, you can still address them if you have a pointer to the Top struct: 如果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()
    }
}

"Top.S1" is of type "T1" and is different from "*T1" type defined "Validate()". “ Top.S1”的类型为“ T1”,与定义为“ Validate()”的“ * T1”类型不同。

If you change "Top.S1" to "*T1" type and modify the field type checking, your code will work properly. 如果将“ Top.S1”类型更改为“ * T1”类型并修改字段类型检查,则代码将正常工作。

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 https://play.golang.org/p/hHqP6WdMYqT

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

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