【问题标题】:Using reflection to iterate over struct's struct members and calling a method on it使用反射迭代结构的结构成员并在其上调用方法
【发布时间】:2018-03-07 22:40:34
【问题描述】:

我有一个struct,它有一个或多个struct 成员。每个成员都应该实现一个Validator 接口。

我想使用反射来遍历所有struct 成员并调用接口的Validate() 方法。例如:

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

运行时输出:

panic:接口转换:main.T1 不是 main.Validator:缺少方法 Validate

如果我将 Validate() 方法更改为接受值(而不是指针)接收器,那么它可以工作。但是,我使用指针接收器,因为 structs 可能会变得很大。

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

我也试过用这条线:

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

获取一个指针,然后输出:

恐慌:reflect.Value.Addr 的不可寻址值

【问题讨论】:

    标签: go methods struct reflection interface


    【解决方案1】:

    你的值都不是可寻址的,所以你不能用指针接收器调用它们的任何方法。

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

    【讨论】:

      【解决方案2】:

      “Top.S1”属于“T1”类型,不同于“*T1”类型定义的“Validate()”。

      如果你把“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

      【讨论】:

      • JimB 的回答不需要更改数据结构。
      猜你喜欢
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 2019-04-15
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多