go – Golang: pointer to function from string (function's name)-ThrowExceptions

Exception or error:

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.

How to solve:

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

Playground


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

Answer:

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

Inspiration/source

Answer:

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.

Answer:

If the function is a ‘Method’, you can use reflect.Value.MethodByName

see reflect documentation here

Leave a Reply

Your email address will not be published. Required fields are marked *