【问题标题】:Run function from a package by reflecting its name通过反映其名称从包中运行函数
【发布时间】:2021-10-28 02:37:16
【问题描述】:

目前我将包名称作为字符串"Forecast",我需要将此字符串反映到一个包中,以便我可以调用函数Run()。有没有办法进行这种反思?

为什么?

目前我正在 golang 中构建一个任务运行器,其中所有任务都具有 Run() 函数,并且我通过 kafka 消息 "task": "Forecast" 接收要运行的任务,所以我试图避免 switch 之类的:

switch message.Task {
  case "Forecast":
    Forecast.Run()
  case "SupplyCalculator":
    SupplyCalculator.Run()
}

而只是反映名称并调用函数,像这样(PHP):

$task = new ReflectionClass("\\Task\\{$message->task}");
$task->run();

【问题讨论】:

  • 你不能在 Go 中对包使用反射。如果您不喜欢使用switch,请考虑使用地图。
  • 你考虑过使用go generate来生成switch语句吗?

标签: go


【解决方案1】:

包不是 Go 中的类型。

给定一个包foo 和一个函数Run,这可行...

v := reflect.ValueOf(foo.Run)
fmt.Println(v.Kind()) // func

但这是一个语法错误:

v := reflect.ValueOf(foo)

不要尝试使用反射,而是提前在映射中注册函数,然后在映射中查找正确的函数来调用它。您可以提供一个简单的tasks 包来执行此操作,使用RegisterRun 等方法。

// tasks.go
package tasks

type TaskFunc func() error // or whatever arguments your tasks take
var taskFuncs = map[string]TaskFunc{}

func Register(name string, fn TaskFunc) {
  taskFuncs[name] = fn
}

func Run(name string) error {
  if fn, found := taskFuncs[name]; found {
    return fn()
  }
  return fmt.Errorf("Task %q not found", name)
}
// forecast.go
package forecast

import "tasks"

tasks.Register("forecast", Run)

func Run() error {
   // ...
}

// main.go

err := tasks.Run(message.Task)

【讨论】:

  • 这是这样做的方法:+1:
  • 您的forecast.go 无效 - 顶层不允许进行裸函数调用。这应该在 init() 函数中。
  • @Adrian 不打算运行的伪代码。您还会注意到 main.go 是同样无效的 sn-p。
  • @meagar 您可能希望在答案中更清楚地说明这一点。 main.go sn-p 看起来不完整,forecast.go sn-p 没有;看起来它是为了描绘一个完整的 go 文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多