21

I need to walk through all the field of a struct type and check if they implements a given interface.

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

Then, if a call HasModels with a struct like so :

type Company struct {...}

type User struct {
    ...
    Company Company
}

HasModels(&User{})

With Company and User both implementing Model; I get f.Type.Implements(ModelType) returning false for the Company field of the User struct.

This is unexpected, so, what Am I doing wrong here ?

3 Answers 3

32

You've unfortunately left out the essential parts (please always post complete programs), so I can only guess that the problem is in a method defined on a pointer receiver, in which case the behavior of your code is expected. Check this example and its output:

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


Output:

0: CompanyA main.Company -> true
1: CompanyB *main.Company -> true
2: DepartmentA main.Department -> false
3: DepartmentB *main.Department -> true
Sign up to request clarification or add additional context in comments.

1 Comment

you're guessing right. I just changed f.Type.Implements(modelType) to reflect.PtrTo(f.Type).Implements(modelType) and it works perfectly. Thx for the fast answer.
13

There's an easier way of doing this that doesn't need reflect. For example:

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

calls the Middleware() method only in those slice elements that implement the middlewarer interface.

2 Comments

Except this doesn't relate to the OP\s question which does not have a slice of anything. They have only a struct and wish to check each field of that.
you didn't answer the op's question, but you did give a proper way to check if a struct implements a given struct, which is exactly what shows in the title.
2

If the variable is not an interface, make it one.

foo := interface{}(yourVar)

Then you can check if it implements the interface you're interested in.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.