【问题标题】:Check if struct implements a given interface检查结构是否实现给定接口
【发布时间】:2013-09-05 09:30:02
【问题描述】:

我需要遍历结构类型的所有字段并检查它们是否实现了给定的接口。

type Model interface {...}

func HasModels(m Model) {
    s := reflect.ValueOf(m).Elem()
    t := s.Type()
    modelType := reflect.TypeOf((*Model)(nil)).Elem()

    for i := 0; i < s.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%d: %s %s -> %s\n", i, f.Name, f.Type, f.Type.Implements(modelType)) 
    }       
}

然后,如果调用 HasModels 具有这样的结构:

type Company struct {...}

type User struct {
    ...
    Company Company
}

HasModels(&User{})

Company 和 User 都实现了 Model;我得到 f.Type.Implements(ModelType) 为 User 结构的 Company 字段返回 false。

这是出乎意料的,所以,我在这里做错了什么?

【问题讨论】:

    标签: reflection go


    【解决方案1】:

    不幸的是,您遗漏了基本部分(请始终发布完整的程序),所以我只能猜测问题出在指针接收器上定义的方法中,在这种情况下,您的代码的行为 预期。检查此示例及其输出:

    package main
    
    import (
            "fmt"
            "reflect"
    )
    
    type Model interface {
            m()
    }
    
    func HasModels(m Model) {
            s := reflect.ValueOf(m).Elem()
            t := s.Type()
            modelType := reflect.TypeOf((*Model)(nil)).Elem()
    
            for i := 0; i < s.NumField(); i++ {
                    f := t.Field(i)
                    fmt.Printf("%d: %s %s -> %t\n", i, f.Name, f.Type, f.Type.Implements(modelType))
            }
    }
    
    type Company struct{}
    
    func (Company) m() {}
    
    type Department struct{}
    
    func (*Department) m() {}
    
    type User struct {
            CompanyA    Company
            CompanyB    *Company
            DepartmentA Department
            DepartmentB *Department
    }
    
    func (User) m() {}
    
    func main() {
            HasModels(&User{})
    }
    

    Playground


    输出:

    0: CompanyA main.Company -> true
    1: CompanyB *main.Company -> true
    2: DepartmentA main.Department -> false
    3: DepartmentB *main.Department -> true
    

    【讨论】:

    • 你猜对了。我刚刚将 f.Type.Implements(modelType) 更改为 reflect.PtrTo(f.Type).Implements(modelType) 并且效果很好。谢谢你的快速回答。
    【解决方案2】:

    有一种不需要反思的更简单的方法。例如:

    type middlewarer interface {Middleware() negroni.Handler}
    for _, controller := range ctrls {
        if m, ok := interface{}(controller).(middlewarer); ok {
            n.Use(m.Middleware())
        }
    }
    

    仅在那些实现中间件接口的切片元素中调用 Middleware() 方法。

    【讨论】:

    • 除了这与 OP\s 的问题无关,它 not 有任何东西。他们只有一个结构,并希望检查其中的每个字段。
    • 您没有回答操作员的问题,但您确实给出了检查结构是否实现给定结构的正确方法,这正是标题中显示的内容。
    【解决方案3】:

    如果变量不是接口,则将其设为一个。

    foo := interface{}(yourVar)
    

    然后你可以检查它是否实现了你感兴趣的接口。

    bar, ok := foo.(yourInterface)
    if !ok {
        // handle the case where it doesn't match the interface
    }
    bar.methodOnYourInterface()
    

    Here's a playground link for a more fleshed out example

    【讨论】:

      猜你喜欢
      • 2016-04-02
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      • 2016-09-29
      • 1970-01-01
      • 2018-10-19
      • 2010-09-21
      • 2012-03-06
      相关资源
      最近更新 更多