【问题标题】:How to call method by its string name with string struct name?如何通过字符串名称和字符串结构名称调用方法?
【发布时间】:2023-03-15 08:40:01
【问题描述】:

我有一个结构,在结构定义下有 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)

【问题讨论】:

标签: go methods dynamic struct


【解决方案1】:

调用由其名称给出的某种类型的方法很容易(使用reflection)。看这个例子:

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

不可能在给定字符串名称的情况下“实例化”一个类型,因为如果您的代码没有显式引用该类型,它甚至可能不会包含在可执行二进制文件中。详情见Call all functions with special prefix or suffix in Golang;和Splitting client/server code

一种可能的解决方法是使用某种“类型注册表”,在使用它之前填充它(在你想通过它的名称创建一个值之前)。类型注册表(可能是一个映射)可以保存从类型名称映射的 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2014-10-26
    • 2016-08-09
    • 2023-03-17
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    相关资源
    最近更新 更多