通过反射其名称来运行包中的函数。

huangapple go评论78阅读模式
英文:

Run function from a package by reflecting its name

问题

目前我将包名作为字符串"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();
英文:

Currently I have the package name as a string "Forecast" and I need to reflect this string into a package so that I can call the function Run(). Is there a way to make this reflection?

Why?

Currently I am building a task runner in golang in which all tasks have the function Run() and I receive which task to run by a kafka message "task": "Forecast", so I am trying to avoid a switch like:

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

And instead to just reflect the name and call the function, like this (PHP):

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

答案1

得分: 4

在Go语言中,包(Packages)不是一种类型。

给定一个名为foo的包,其中包含一个名为Run的函数,以下代码是有效的:

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

但是以下代码会导致语法错误:

v := reflect.ValueOf(foo)

不要试图使用反射,而是在一个映射(map)中提前注册函数,然后在该映射中查找正确的函数并调用它。你可以提供一个简单的tasks包来实现这一点,其中包含RegisterRun等方法。

// tasks.go
package tasks

type TaskFunc func() error // 或者根据你的任务需要传入的参数定义
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)
英文:

Packages are not a type in Go.

Given a package foo with a function Run, this works...

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

But this is a syntax error:

v := reflect.ValueOf(foo)

Instead of trying to use reflection, register the functions ahead of time in a map, and then look up the correct function in that map to call it. You can provide a simple tasks package to do this, with methods like Register and Run.

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

huangapple
  • 本文由 发表于 2021年10月28日 02:22:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/69743686.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定