29

In Go, how do you check if an object responds to a method?

For example, in Objective-C this can be achieved by doing:

if ([obj respondsToSelector:@selector(methodName:)]) { // if method exists
  [obj methodName:42]; // call the method
}
nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29

3 Answers3

42

A simple option is to declare an interface with just the method you want to check for and then do a type assert against your type like;

 i, ok := myInstance.(InterfaceImplementingThatOneMethodIcareAbout)
 // inline iface declaration example
 i, ok = myInstance.(interface{F()})

You likely want to use the reflect package if you plan to do anything too crazy with your type; http://golang.org/pkg/reflect

st := reflect.TypeOf(myInstance)
m, ok := st.MethodByName("F")
if !ok {
    // method doesn't exist
} else {
    // do something like invoke m.F
}   
nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29
evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
  • 13
    I'd really encourage folks to use the type assertion rather than reflect (or, better if you have no other need to name a one-method iface, an anonymous interface specified inline like uraimo suggested). Faster, shorter, no import, no strings as method names. – twotwotwo Apr 16 '15 at 20:12
  • @twotwotwo agreed. I think reflect only really makes sense if you're going to do a lot of inspection that leads to runtime decisions about how to behave. If you just want to see whether or not you can invoke a method, the iface option is much simpler and if you're only using it in one place the inline anonymous declaration is better too. – evanmcdonnal Apr 16 '15 at 20:13
  • Then how do i use `m`, since it is `reflect.Method` type? – TomSawyer Nov 25 '19 at 09:04
  • Hmm this doesn't work. https://go.dev/play/p/gOqgNeIXITX , cmiiw – mhd Jun 03 '22 at 11:29
  • @mhd: The compile error for the program is: `invalid operation: gelo (variable of type Gila) is not an interface`. It isn't that the program failed to detect the interface implementation at runtime. It's just that Go, as a language, disallows type assertions on non-interface types, and this error is reported at compile time. – nishanthshanmugham Nov 21 '22 at 18:27
25

If obj is an interface{} you can use Go type assertions:

if correctobj, ok := obj.(interface{methodName()}); ok { 
  correctobj.methodName() 
} 
uraimo
  • 19,081
  • 8
  • 48
  • 55
  • Great example answer, but could you please explain why `interface{methodName()}` works inside of a type assertion? (Why) Is `interface{methodName()}` a type match as opposed to simply `interface{}` and (why) does it work even if the interface has other methods? – chrishiestand Dec 12 '18 at 06:54
  • Then how do i use `correctobj.methodName()` value? `x:=correcorrectobj.methodName()` gives error `correctobj.methodName() used as value` – TomSawyer Nov 25 '19 at 09:07
  • @TomSawyer: the error "correctobj.methodName() used as value" occurs in this particular case, because `methodName`'s signature in the type assertion has no return values. If the signature were, say, `methodName() int`, this error would not occur. – nishanthshanmugham Dec 08 '21 at 21:39
  • 1
    @chrishiestand: The type assertion `obj.(T)` is true if obj has _at least_ the methods listed in T. In the case where T is `interface{methodName()}`, the assertion is true if obj has at least the one listed method. In the case where T is `interface{}`, the type assertion is trivially true always because there are no method requirements to satisfy. [Go playground](https://go.dev/play/p/WUAvXaFzIm4). – nishanthshanmugham Dec 08 '21 at 21:44
0

Just in addition to @evanmcdonnal's solution inside the interface braces {write_function_declaration_here}, you will write the function declaration

if correctobj, ok := obj.(interface{methodName(func_arguments_here)(return_elements_here)}); ok { 
 x,... := correctobj.methodName() 
} 

i.e.

package main

import "fmt"

type test struct {
    fname string
}

func (t *test) setName(name string) bool {
    t.fname = name
    return true
}

func run(arg interface{}) {
    if obj, ok := arg.(interface{ setName(string) bool });
        ok {
        res := obj.setName("Shikhar")
        fmt.Println(res)
        fmt.Println(obj)
    }
}

func main() {
    x := &test{
        fname: "Sticker",
    }
    fmt.Println(x)
    run(x)

}