40

In order to determine whether a given type implements an interface using the reflect package, you need to pass a reflect.Type to reflect.Type.Implements(). How do you get one of those types?

As an example, trying to get the type of an uninitialized error (interface) type does not work (it panics when you to call Kind() on it)

var err error
fmt.Printf("%#v\n", reflect.TypeOf(err).Kind())
dolmen
  • 8,126
  • 5
  • 40
  • 42
laslowh
  • 8,482
  • 5
  • 34
  • 45
  • 3
    This can be helpful: http://stackoverflow.com/questions/6390585/in-golang-is-is-possible-get-reflect-type-from-the-type-itself-from-name-as-str – Yves Junqueira Aug 20 '11 at 17:10
  • This question is so old that it refers to an interface (`os.Error`) that doesn't exists since Go 1.0. – dolmen Sep 28 '20 at 07:52
  • I have fixed the question to replace `os.Error` with `error`. – dolmen Sep 28 '20 at 07:58

3 Answers3

56

Do it like this:

var err error
t := reflect.TypeOf(&err).Elem()

Or in one line:

t := reflect.TypeOf((*error)(nil)).Elem()
leonheess
  • 16,068
  • 14
  • 77
  • 112
Evan Shaw
  • 23,839
  • 7
  • 70
  • 61
  • Imho, if the type to check for is an interface, this will only work if the interface method is implemented on the "naked" receiver, not on the pointer receiver, so beware of that case. – andig Jan 14 '19 at 19:04
  • 1
    @andig Not true. If we're talking about an interface, as opposed to an implementation of an interface, the methods are always on the interface type itself. Never on a pointer to the interface. (In fact, if you try to call an interface method on a pointer to an interface, the compiler will complain.) – Evan Shaw Jan 15 '19 at 18:59
  • This syntax for Go is ridiculously confusing. What is `(nil)` doing after the pointer to `(*error)`? Why does `(*error)` need to be a pointer in the first place? It would make a lot more sense to simply specify the name of the interface type, instead of a pointer. Something like: `reflect.TypeOf(error)`. – Trevor Sullivan Apr 22 '23 at 20:05
13

Even Shaws response is correct, but brief. Some more details from the reflect.TypeOf method documentation:

// As interface types are only used for static typing, a common idiom to find
// the reflection Type for an interface type Foo is to use a *Foo value.

writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()

fileType := reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(fileType.Implements(writerType))
Dionysius
  • 488
  • 5
  • 10
Kristoffer
  • 131
  • 1
  • 5
-1

For googlers out there I just ran into the dreaded scannable dest type interface {} with >1 columns (XX) in result error.

Evan Shaw's answer did not work for me. Here is how I solved it. I am also using the lann/squirrel library, but you could easily take that out.

The solution really isn't that complicated, just knowing the magic combination of reflect calls to make.

The me.GetSqlx() function just returns an instance to *sqlx.DB

    func (me *CommonRepo) Get(query sq.SelectBuilder, dest interface{}) error {
      sqlst, args, err := query.ToSql()
      if err != nil {
        return err
      }
      // Do some reflection magic so that Sqlx doesn't hork on interface{}
      v := reflect.ValueOf(dest)
      return me.GetSqlx().Get(v.Interface(), sqlst, args...)
    }
    func (me *CommonRepo) Select(query sq.SelectBuilder, dest interface{}) error {
      sqlst, args, err := query.ToSql()
      if err != nil {
        return err
      }
      // Do some reflection magic so that Sqlx doesn't hork on interface{}
      v := reflect.ValueOf(dest)
      return me.GetSqlx().Select(v.Interface(), sqlst, args...)
    }

Then to invoke it you can do:

    func (me *myCustomerRepo) Get(query sq.SelectBuilder) (rec Customer, err error) {
      err = me.CommonRepo.Get(query, &rec)
      return
    }
    func (me *myCustomerRepo) Select(query sq.SelectBuilder) (recs []Customer, err error) {
      err = me.CommonRepo.Select(query, &recs)
      return
    }

This allows you to have strong types all over but have all the common logic in one place (CommonRepo in this example).

Andrew Burns
  • 13,917
  • 9
  • 40
  • 42
  • 4
    First, `me` (or `this` or `self`) are not good receiver names (even in languages that require one of those); idiomatic Go uses receiver names appropriate to the type. Second, surely `v := reflect.ValueOf(dest); x := v.Interface()` is [just a round about way of doing `x := dest`](https://play.golang.org/p/kYReCv97QD)? (Or `var x interface{} = dest` if `dest` was not already of type `interface{}`). – Dave C Jun 18 '15 at 14:18
  • Answers targeted to people from a single company (whatever how big it is) are irrelevant here. – dolmen Sep 28 '20 at 07:45
  • 2
    @dolmen pretty sure they just meant people googling, not people working at Google. – Qix - MONICA WAS MISTREATED Oct 06 '21 at 19:43
  • Not only is this bad (for the reasons @DaveC mentioned), it also doesn't answer the question! – Adam B Mar 24 '22 at 14:57