You can’t do this in Go. The compiler can omit functions that aren’t referenced in the code, for example, given:
package main
import "fmt"
func main() {
fmt.Println("test")
}
func MyFunc(a, b int) int { return a + b }
type MyType struct{ S string }
MyFunc
and MyType
might not exist in the compiled binary because neither are ever referenced. This is why Go doesn’t offer things like looking up types by their names from the reflect
package; you can only get exported member functions of a type via the reflect
package if the code you build references that type somewhere; that’s the only way to be sure that the compiler included the type at all.
The way around this is to build a map yourself of the functionality you need:
package main
import "fmt"
func main() {
fmt.Println(myMap)
}
var myMap = map[string]interface{}{
"MyFunc": MyFunc,
"MyType": reflect.TypeOf(MyType{}),
}
func MyFunc(a, b int) int { return a + b }
type MyType struct{ S string }
This way, we’re sure that MyFunc
and MyType
are defined because they’re referenced by myMap
and myMap
is referenced from main
.
Shameless Plug:
All that being said, I wanted to be able to do something similar to what you’re asking, so I made a package, github.com/skillian/pkgsyms, that generates the necessary code to do this.
You have to execute a command to generate the code:
pkgsyms -package mypkg -output=fmtsyms.go fmt
(You can put it in a //go:generate
comment in your program)
Which would generate a file like this:
// Code generated by "pkgsyms -varname fmtPkg -package mypkg -output fmtsyms.go fmt"; DO NOT EDIT.
package mypkg
import (
"github.com/skillian/pkgsyms"
"fmt"
)
var fmtPkg = pkgsyms.Of("fmt")
func init() {
fmtPkg.Add(
pkgsyms.MakeType("Formatter", (*fmt.Formatter)(nil)),
pkgsyms.MakeType("GoStringer", (*fmt.GoStringer)(nil)),
pkgsyms.MakeType("ScanState", (*fmt.ScanState)(nil)),
pkgsyms.MakeType("Scanner", (*fmt.Scanner)(nil)),
pkgsyms.MakeType("State", (*fmt.State)(nil)),
pkgsyms.MakeType("Stringer", (*fmt.Stringer)(nil)),
pkgsyms.MakeFunc("Errorf", fmt.Errorf),
pkgsyms.MakeFunc("Fprint", fmt.Fprint),
pkgsyms.MakeFunc("Fprintf", fmt.Fprintf),
pkgsyms.MakeFunc("Fprintln", fmt.Fprintln),
pkgsyms.MakeFunc("Fscan", fmt.Fscan),
pkgsyms.MakeFunc("Fscanf", fmt.Fscanf),
pkgsyms.MakeFunc("Fscanln", fmt.Fscanln),
pkgsyms.MakeFunc("Print", fmt.Print),
pkgsyms.MakeFunc("Printf", fmt.Printf),
pkgsyms.MakeFunc("Println", fmt.Println),
pkgsyms.MakeFunc("Scan", fmt.Scan),
pkgsyms.MakeFunc("Scanf", fmt.Scanf),
pkgsyms.MakeFunc("Scanln", fmt.Scanln),
pkgsyms.MakeFunc("Sprint", fmt.Sprint),
pkgsyms.MakeFunc("Sprintf", fmt.Sprintf),
pkgsyms.MakeFunc("Sprintln", fmt.Sprintln),
pkgsyms.MakeFunc("Sscan", fmt.Sscan),
pkgsyms.MakeFunc("Sscanf", fmt.Sscanf),
pkgsyms.MakeFunc("Sscanln", fmt.Sscanln),
)
}
Then if you wanted to lookup and call fmt.Println
from your code, you could do this:
package main
import (
"log"
"github.com/skillian/pkgsyms"
)
func main() {
f, err := pkgsyms.Of("fmt").Lookup("Println")
if err != nil {
log.Fatal(err)
}
printlnFunc := f.Get().(func(...interface{}) (int, error))
printlnFunc("Hello, world")
}