如何通过字符串结构名调用其方法名称?

7
我有一个结构体,在结构体定义下有2个方法,我想在其他地方调用它们,使用结构体名称和方法名称作为参数。
结构体代码如下:
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"`
}

以下是方法定义:
func (this *ArticleForm) GetTagOptions() []Tags {
return GetTagsOptions(nil)
}

以下是我想要打电话的内容:
func main() {
s := "models.ArticleForm"
t := "GetTagOptions"
//following is the question, how can i exec following?
funcall(s,t)
}

如何执行funcall(s, t)?

请参考 https://dev59.com/RGkv5IYBdhLWcg3w_lvE 了解如何根据字符串创建一个类型的实例。 - Charlie Tumahai
Switch Case 可以是一个简单的解决方案。 - Rajan
1个回答

24

通过使用反射,可以很容易地根据其名称调用某个类型的方法。请参考以下示例:

type My struct{}

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

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

输出(在Go Playground上尝试):

MyFunc called

“实例化”一个类型,给定其字符串名称是不可能的,因为如果您的代码没有明确引用该类型,则它甚至可能不包含在可执行二进制文件中。有关详细信息,请参见在Golang中使用特殊前缀或后缀调用所有函数;和拆分客户端/服务器代码
一种可能的解决方法是使用某种“类型注册表”,在使用之前填充它(在您要按名称创建值之前)。类型注册表(可以是映射)可以保存从类型名称映射的reflect.Type值或工厂函数。
按照上述My类型声明,存储reflect.Type值的类型注册表可能如下所示(请在Go Playground上尝试):
registry := map[string]reflect.Type{
    "My": reflect.TypeOf((*My)(nil)).Elem(),
}

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

一个存储工厂函数的注册表可能看起来像这样(在Go Playground上尝试):

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

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

如何向 MyFunc 添加参数? - MohNj
@MohNj 像这样:func (m My) MyFunc(paramName paramType) {} - icza
有没有一种方法可以在不使用反射的情况下调用它们?我正在考虑使用适配器模式。对此有何想法? - karthikeyan
1
@karthikeyan 这个链接的问题展示了其他调用它的方式:使用特殊前缀/后缀调用函数 - icza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接