6

I have one struct with 2 methods under struct definition, I want to call in other place that use struct's name and method's name as param.

Struct code as following:

type ArticleForm struct {
Name     string     `required:"true" pattern:"^[A-Za-z0-9\u4e00-\u9fa5]{1,1024}$" valid:"Required;MaxSize(1024)"`
Category []Category `class:"multis" required:"true" valid:"Required" optionqs:"GetCategoryOption"`
Content  string     `class:"wysiwg_area" required:"true" valid:"Required"`
Tags     []Tags     `class:"multis_create" optionqs:"GetTagOptions"`
}

Method definition as following:

func (this *ArticleForm) GetTagOptions() []Tags {
return GetTagsOptions(nil)
}

Following is what I want to call:

func main() {
s := "models.ArticleForm"
t := "GetTagOptions"
//following is the question, how can i exec following?
funcall(s,t)
}

How to fulfill the funcall(s,t)?

icza
  • 389,944
  • 63
  • 907
  • 827
user3818534
  • 61
  • 1
  • 1
  • 2

1 Answers1

23

Calling a method of some type given by its name is easy (using reflection). See this example:

type My struct{}

func (m My) MyFunc() {
    fmt.Println("MyFunc called")
}

func main() {
    m := My{}
    meth := reflect.ValueOf(m).MethodByName("MyFunc")
    meth.Call(nil)
}

Output (try it on the Go Playground):

MyFunc called

"Instantiating" a type given its string name is not possible, because if your code does not explicitly refer to the type, it may not even be included in the executable binary. For details, see Call all functions with special prefix or suffix in Golang; and Splitting client/server code.

A possible workaround is to use some kind of "type-registry" which you populate prior to using it (before you want to create a value by its name). The type registry (which may be a map) may hold reflect.Type values or factory functions mapped from the type name.

Following the above My type declaration, a type registry storing reflect.Type values may look like this (try it on the Go Playground):

registry := map[string]reflect.Type{
    "My": reflect.TypeOf((*My)(nil)).Elem(),
}

v := reflect.New(registry["My"]).Elem()
v.MethodByName("MyFunc").Call(nil)

And a registry that stores factory functions could look like this (try it on the Go Playground):

registry := map[string]func() interface{}{
    "My": func() interface{} { return My{} },
}

v := registry["My"]()
meth := reflect.ValueOf(v).MethodByName("MyFunc")
meth.Call(nil)
Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
  • how to add arguments to `MyFunc`? – MohNj Sep 03 '22 at 17:31
  • @MohNj Like this: `func (m My) MyFunc(paramName paramType) {}` – icza Sep 03 '22 at 17:44
  • Is there a way I can call them without reflection? I was thinking of adapter pattern. Any thoughts on the same? – karthikeyan Dec 20 '22 at 07:47
  • 1
    @karthikeyan The linked question shows other ways to call it: [Call functions with special prefix/suffix](https://stackoverflow.com/questions/37384473/call-functions-with-special-prefix-suffix/37384665#37384665) – icza Dec 20 '22 at 07:56