Is there any chance to get pointer to function from function's name, presented as string? This is needed for example to send some function as argument to another function. Some sort of metaprogramming, you know.
4 Answers
Go functions are first class values. You don't need to revert to the tricks from dynamic languages.
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))
}
Output:
123
99
If the selection of the function depends on some run-time-only known value, you can use a map:
m := map[string]func(int, int) int {
"someFunction1": someFunction1,
"someFunction2": someFunction2,
}
...
z := someOtherFunction(x, y, m[key])
11 Comments
"foo"), pass the function's identifier in quotation marks. Both techniques are shown above. Or I didn't get what you mean, perhaps?The accepted answer answer is probably what you should do.
Here is an approach using reflection that allows to pass a flexible number of arguments as well. Currently it requires building a list (map) of supported functions manually (see main method), but this could be improved.
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)
}
1 Comment
If the function is a 'Method', you can use reflect.Value.MethodByName
4 Comments
I'm not entirely clear on what you're wanting to do. The accepted answer should cover the fundamentals of anything you're trying to do.
I would like to add that the crypto package has an interesting way of indirectly registering other packages. Specifically take a look at crypto.go.
Essentially how it works is the crypto package has an empty map like this:
var regFuncs = make(map[key]func (arg) result)
Where "key" would be a unique type (of int, string, etc..) and the value would be the function prototype you're expecting.
A package would then register itself using the init function:
func init() {
master.RegisterFunc("name", myFunc)
}
The package itself would be included using import _ "path/to/package".
And then the master package would have some way of fetching that function.
With crypto, you can use sha 256 like this:
crypto.SHA256.New()
But you have to first include it in your main like this:
import _ "crypto/sha256"
Hopefully that helps.