1

I've got a handful of interfaces, and n number of structs that arbitrarily implement these interfaces. I'd like to keep an array of types and be able to run a loop over them to see which ones are implemented. Is it possible to store a type like this? I spent a little bit of time with the reflect package, but couldn't really find what I was looking for, I understand if maybe this isn't best practice. Trying to do something similar to this.. without a giant type switch, fallthrough, or if.. if... if.

type InterOne interface {
    InterOneMethod() string
}

var interfaceMap = map[string]type {
    "One": InterOne,
    ...
}

func doesHandle(any interface{}) []string {
    var handles []string
    for k, v := range interfaceMap {
      if _, ok := any.(v); ok {
          handles = append(handles, k)
      }
    }
    return handles
}

EDIT: The answer marked as correct is technically right. I found that due to the comment about the method calling & the overuse of reflection, that this approach was a bad idea. Instead I went with a type switch to check for a single interface because fallthrough is not supported on type switch, and a large if.. if.. if.. with type assertions to be able to make the appropriate calls.

estobbart
  • 1,137
  • 12
  • 28
  • Not sure why you'd want to do something like this, but if you're not planning on reusing `interfaceMap` elsewhere, then a bunch of `if`s is probably a simpler way to implement this: http://play.golang.org/p/eSUf2xSqI7. – Amit Kumar Gupta Apr 18 '16 at 02:54
  • Not sure I'd really reuse it, it's just a example of what I'm aiming for. – estobbart Apr 18 '16 at 02:56

1 Answers1

2

You can use reflect, notice that to get the type of an interface the only way is to use reflect.TypeOf((*INTERFACE)(nil)).Elem(), here's a working example:

var interfaceMap = map[string]reflect.Type{
    "One": reflect.TypeOf((*InterOne)(nil)).Elem(),
....
}

func doesHandle(any interface{}) []string {
    t := reflect.TypeOf(any)
    var handles []string
    for k, v := range interfaceMap {
        if t.Implements(v) {
            handles = append(handles, k)
        }
    }
    return handles
}

playground

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • This looks exactly like what I want, whats the difference between reflect.TypeOf((*InterOne)(nil)) and reflect.TypeOf((*InterOne)(nil)).Elem(), both are reflect.Type right? – estobbart Apr 18 '16 at 03:03
  • Is it also possible to call the InterOneMethod on any? Normally I'd do a type assertion first. – estobbart Apr 18 '16 at 03:10
  • `reflect.TypeOf((*InterOne)(nil))` returns a pointer to the interface, which is pretty much not valid. you can call InterOneMethod using reflect.ValuOf(any).MethodByName but calling functions like that is extremely slow. – OneOfOne Apr 18 '16 at 03:27