8

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)?

1
  • Switch Case can be a simple solution. Commented Jan 8, 2022 at 11:07

1 Answer 1

26

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)
Sign up to request clarification or add additional context in comments.

4 Comments

how to add arguments to MyFunc?
@MohNj Like this: func (m My) MyFunc(paramName paramType) {}
Is there a way I can call them without reflection? I was thinking of adapter pattern. Any thoughts on the same?
@karthikeyan The linked question shows other ways to call it: Call functions with special prefix/suffix

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.