Golang:从字符串(函数名称)指向函数的指针

时间:2013-08-02 13:22:34

标签: go

是否有机会从函数名称获取函数指针,以字符串形式显示?这需要例如将一些函数作为参数发送到另一个函数。你知道某种元编程。

谢谢!

4 个答案:

答案 0 :(得分:39)

Go函数是第一类值。您无需恢复动态语言的技巧。

package main

import "fmt"

func someFunction1(a, b int) int {
        return a + b
}

func someFunction2(a, b int) int {
        return a - b
}

func someOtherFunction(a, b int, f func(int, int) int) int {
        return f(a, b)
}

func main() {
        fmt.Println(someOtherFunction(111, 12, someFunction1))
        fmt.Println(someOtherFunction(111, 12, someFunction2))
}

Playground


输出:

123
99

如果函数的选择取决于某些仅限运行时的已知值,则可以使用映射:

m := map[string]func(int, int) int {
        "someFunction1": someFunction1,
        "someFunction2": someFunction2,
}

...

z := someOtherFunction(x, y, m[key])

答案 1 :(得分:14)

The accepted answer回答可能是你应该做的。

这是一种使用反射的方法,它允许传递灵活数量的参数。目前,它需要手动构建支持函数的列表(映射)(请参阅main方法),但这可以改进。

package main

import "fmt"
import "reflect"
import "errors"

func foo() {
    fmt.Println("we are running foo")
}

func bar(a, b, c int) {
    fmt.Println("we are running bar", a, b, c)
}

func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value, err error) {
    f := reflect.ValueOf(m[name])
    if len(params) != f.Type().NumIn() {
        err = errors.New("The number of params is not adapted.")
        return
    }
    in := make([]reflect.Value, len(params))
    for k, param := range params {
        in[k] = reflect.ValueOf(param)
    }
    result = f.Call(in)
    return
}

func main() {
    // nota bene: for perfect score: use reflection to build this map
    funcs := map[string]interface{} {
            "foo": foo,
            "bar": bar,
    }

    Call(funcs, "foo")
    Call(funcs, "bar", 1, 2, 3)
}

Inspiration/source

答案 2 :(得分:3)

我不清楚你想做什么。 The accepted answer应涵盖您尝试做的任何事情的基本原理。

我想补充一点,crypto包有一种间接注册其他包的有趣方式。具体来看看crypto.go

基本上它是如何工作的crypto包有一个像这样的空地图:

var regFuncs = make(map[key]func (arg) result)

其中“key”是一个唯一的类型(int,string等),值将是你期望的函数原型。

然后包将使用init函数注册自己:

func init() {
    master.RegisterFunc("name", myFunc)
}

包裹本身将使用import _ "path/to/package"包含。

然后主包可以通过某种方式获取该功能。

使用crypto,您可以像这样使用sha 256:

crypto.SHA256.New()

但你必须首先将它包含在你的主体中:

import _ "crypto/sha256"

希望这有帮助。

答案 3 :(得分:1)

如果函数是'方法',则可以使用reflect.Value.MethodByName

请参阅reflect documentation here