How to check if an object has a particular method?
Asked Answered
B

3

33

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
}
Burble answered 16/4, 2015 at 19:48 Comment(0)
G
44

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
}   
Gaudery answered 16/4, 2015 at 19:59 Comment(5)
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.Flavopurpurin
@Flavopurpurin 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.Gaudery
Then how do i use m, since it is reflect.Method type?Purposive
Hmm this doesn't work. go.dev/play/p/gOqgNeIXITX , cmiiwLaster
@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.Burble
P
27

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

if correctobj, ok := obj.(interface{methodName()}); ok { 
  correctobj.methodName() 
} 
Peshawar answered 16/4, 2015 at 19:59 Comment(4)
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?Mamba
Then how do i use correctobj.methodName() value? x:=correcorrectobj.methodName() gives error correctobj.methodName() used as valuePurposive
@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.Burble
@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.Burble
D
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)

}
Darkling answered 24/5, 2021 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.