简体   繁体   中英

Getting list of exported functions from a package in golang

Let's say I have some package

// ./somepkg/someFile.go
package somepkg
import "fmt"
func AnExportedFunc(someArg string) {
    fmt.Println("Hello world!")
    fmt.Println(someArg)
)

and I import it from my main go file

// ./main.go
package main
import (
    "./somepkg" // Let's just pretend I have the full path written out
    "fmt"
)

func main() {
    fmt.Println("I want to get a list of exported funcs from package 'somefolder'")
}

Is there a way to get access to the exported functions from package 'somepkg' and then to consequently call them? Argument numbers/types would be consistent across all functions in somepkg. I've looked through the reflection package but I'm not sure if I can get the list and call the functions without knowing any information other than package name. I may be missing something from the godocs however, so any advice is appreciated. What I'm trying to do is essentially have a system where people can drop in.go files as a sort of "plugin". These "plugins" will have a single exported function which the main program itself will call with a consistent number and types of args. Access to this codebase is restricted so there are no security concerns with arbitrary code execution by contributors.

Note: This is all compiled so there are no runtime restrictions

What I'm trying to do is something like this if written in python

# test.py
def abc():
    print "I'm abc"

def cba():
    print "I'm cba"

and

# foo.py
import test
flist = filter(lambda fname: fname[0] != "_", dir(test))

# Let's forget for a moment how eval() is terrible
for fname in flist:
    eval("test."+fname+"()")

running foo.py returns

I'm abc
I'm cba

Is this possible in golang?

Edit:

I should note that I have already "accomplished" this with something very similar to http://mikespook.com/2012/07/function-call-by-name-in-golang/ but require that each additional "plugin" add its exported function to a package global map. While this "works", this feels hacky (as if this whole program isn't... lol;) and would prefer if I could do it without requiring any additional work from the plugin writers. Basically I want to make it as "drop and go" as possible.

The easiest way to do this is to use the template library to parse your code and insert the new package name where appropriate.

Playground

You can use this by loading all of the finals where you call the user package and then output the generated file to the execution directory.

As you might've guessed, it is difficult to achieve in Go, if not impossible, as Go is a compiled-language.

Traversing a package for exported functions can only get you the list of functions. A sample for this is: Playground . This is a AST (Abstract Syntax Tree) method which means calling the functions dynamically is not possible, or requires too much of workarounds. Parsing function name string as function type doesn't work here.

Alternatively, you can use try methods by binding the exported functions to some type.

type Task struct {}
func (Task) Process0()
func (Task) Process1(v int)
func (Task) Process2(v float64)
func (Task) Process3(v1 bool, v2 string)

This totally changes the way we operate as the 4 methods are now associated with a type Task and we can pass empty instance of Task to call the methods defined on it. This might look like just another workaround, but is very common in languages like Go. A sample for this in Playground which actually works as expected.


In both the examples, I've used multiple files in playground. If you are not familiar with this structure, just create your workspace in your local as following and copy the code under each file name from playground:

<Your project>
├── go.mod
├── main.go
└── task
    └── task.go

References:

  1. How to dynamically call all methods of a struct in Golang? [duplicate]
  2. How to inspect function arguments and types [duplicate]
  3. How do I list the public methods of a package in golang [duplicate]
  4. Abstract Syntax Tree - Wiki
  5. Functions vs Methods in Go

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM