Go: lookup function by name
Asked Answered
B

3

9

I am new to type safe, and can't figure out how to do following

package main

func test(){
    print("In Test")
}

func main(){
    a := "test"
    a()
}
Branscum answered 26/8, 2012 at 4:22 Comment(4)
Have you read any of the Go docs like e.g. the language specs before asking?Glosseme
Do you have a PHP background, perhaps? Note that not all features of PHP are good features for a programming language.Gregoriogregorius
OP also asked this on the go-nuts mailing list, it's quite a good topic (+1 for unfair downvotes): groups.google.com/forum/?fromgroups=#!topic/golang-nuts/…Logomachy
Have you looked at various eval packages for go? Something like go-eval?Incombustible
W
15

You might get better answers if you state what you're trying to achieve, as reflection is usually not the best way. But reflect will help if the functions are methods on a type (net/rpc is an example of this).

package main

import (
    "fmt"
    "reflect"
)

type T struct {}

func (T) Add(x, y int) int {
    return x + y
}

func main() {
    t := reflect.ValueOf(T{})
    m := t.MethodByName("Add")
    args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
    fmt.Println(m.Call(args)[0].Int())
}

If you were wondering how tools like godoc work, they parse the source rather than use reflection.

Edit: Playground version

Wash answered 26/8, 2012 at 10:42 Comment(0)
S
8

A function can not be resolved from a string. However, you can assign a function to a variable.

a := test
a()

You can also put functions (assuming they all have the same signature) into a map:

var func_map :=  map[string]func() {
    "test": test,
}
a := func_map["test"]
a()


Response to first comment by OP (too long to make another comment):

  1. A function is not a "literal". "Literal" has a separate meaning.
  2. Second, Go's runtime reflection does not have a lookup table mapping strings to functions. Even if it did, functions are not linked into the binary unless linked to by other code. Code only called in this method would not be in the binary.
  3. Third, making a mapping manually is not that hard. It provides compile time type safety checks as well as security.
  4. This is not something you should be doing in any language. It is like eval(), you really should not use it because it can be incredibly dangerous and cause unpredictable things to happen.

They don't all have the same signature

If they don't all have the same signature, how do you plan to call them? You could use the reflect package, but that is normally an indication that you are doing something wrong.

This is not a dynamic language and some things can not be done in Go. Although, they are mostly things you should not do in most languages anyways.

Sidon answered 26/8, 2012 at 4:25 Comment(2)
They don't all have the same signature, and also what would be the sense of that. I would have to map all the functions first. This is supposed to be a computer not a note pad. There is got to be a way of turning strings in to their literals.Branscum
See my comments in the answer.Sidon
P
8

There's no way to dynamically look up a function by name, but I think it's worth mentioning why. Basically, the reason is so that the compiler and/or linker can eliminate unused functions.

Consider that if you were able to get a function by name, then every function in every imported package (recursively) would have to be linked into the final executable, even if it was never used, just in case someone wanted to look it up by name. People already complain about the large size of Go binaries, but this would cause them to be much larger still.

Plotter answered 26/8, 2012 at 7:30 Comment(2)
Well, that is not what I am trying to do here. I just wont to look though the list of functions, which are already imported / loaded and available.Branscum
That's equivalent to dynamically getting a function by name.Plotter

© 2022 - 2024 — McMap. All rights reserved.