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 ?
To declare a class that implements an interface, you include an implements clause in the class declaration. Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.
Implementing an interface in Go To implement an interface, you just need to implement all the methods declared in the interface. Unlike other languages like Java, you don't need to explicitly specify that a type implements an interface using something like an implements keyword.
Go language interfaces are different from other languages. In Go language, the interface is a custom type that is used to specify a set of one or more method signatures and the interface is abstract, so you are not allowed to create an instance of the interface.
Type assertions in Golang provide access to the exact type of variable of an interface. If already the data type is present in the interface, then it will retrieve the actual data type value held by the interface. A type assertion takes an interface value and extracts from it a value of the specified explicit type.
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
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With