Golang: pointer to function from string (function's name)

前端 未结 4 818
难免孤独
难免孤独 2020-12-13 03:03

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.

相关标签:
4条回答
  • 2020-12-13 03:31

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

    see reflect documentation here

    0 讨论(0)
  • 2020-12-13 03:36

    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

    0 讨论(0)
  • 2020-12-13 03:43

    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])
    
    0 讨论(0)
  • 2020-12-13 03:52

    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.

    0 讨论(0)
提交回复
热议问题