Skip to content

Instantly share code, notes, and snippets.

@protosam
Created October 21, 2021 04:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save protosam/7659c33168a2b353b3a9ab8cb1629281 to your computer and use it in GitHub Desktop.
Save protosam/7659c33168a2b353b3a9ab8cb1629281 to your computer and use it in GitHub Desktop.
This example shows how to use reflect to work with functions
package main
import (
"fmt"
"log"
"reflect"
)
// a map of functions to be dynamically called...
var funcMap = make(map[string]interface{})
// a struct that some funcs may be passed if they ask for it
type SharedStuff struct {
Somevar string
SomeCounter int
}
func (s *SharedStuff) SaySomething() {
fmt.Println("\tsomeone called SaySomething()")
}
// a sharable *SharedStuff
var sharedstuff = &SharedStuff{}
// some functions for the funcMap
// ------------------------------
// add funcs to the funcMap
func init() {
// no args, no output
funcMap["myfunc1"] = func() {
fmt.Println("\tmyfunc1 doesn't have output but it called println")
}
// no args, just output
funcMap["myfunc2"] = func() string {
return "hello world"
}
// one arg of string, just output
funcMap["myfunc3"] = func(s string) string {
reversed_s := ""
for i := len(s) - 1; i >= 0; i-- {
reversed_s += string(s[i])
}
return reversed_s
}
// multiple args, multiple outputs
funcMap["myfunc3"] = func(s string, i int, ok bool) (string, int, bool) {
reversed_s := ""
for i := len(s) - 1; i >= 0; i-- {
reversed_s += string(s[i])
}
return reversed_s, i + 1, !ok
}
// a shared stuff test
funcMap["myfunc4"] = func(shared *SharedStuff, s string) string {
shared.Somevar = "set by myfunc4"
shared.SaySomething()
return s
}
// a shared stuff test
funcMap["myfunc5"] = func(shared *SharedStuff, s string) string {
return "myfunc5:shared.Somevar: " + shared.Somevar
}
}
// do some function analysis, call them, and return any outputs
func main() {
// iterate funcMap and investigate each one
for fnname, fn := range funcMap {
fmt.Printf("########################################\n")
fmt.Printf("Investigating function: %s\n", fnname)
// reflect the method
method := reflect.ValueOf(fn)
// make sure it's actually a func
if method.Kind().String() != "func" {
log.Fatalf("expected a func but got kind %s", method.Kind().String())
}
// how many inputs/arguments/parameters it has
fmt.Printf("INPUTS: %#v\n", method.Type().NumIn())
// store selected inputs
method_call_inputs := make([]reflect.Value, 0)
// iterate and inspect each input
for i := 0; i < method.Type().NumIn(); i++ {
// select an input based on the reflect.Type value provided by In()
selected := inputSelector(method.Type().In(i))
fmt.Printf("Selected input: %#v\n", selected)
// store the selected input
method_call_inputs = append(method_call_inputs, reflect.ValueOf(selected))
}
// call the method and get outputs
fmt.Printf("CALLCT: %d\n", len(method_call_inputs))
outputs := method.Call(method_call_inputs)
// iterate all the outputs
fmt.Printf("OUTPUTS: %d\n", len(outputs))
for x := range outputs {
fmt.Printf("[%d]%s: %#v\n", x, outputs[x].Kind().String(), outputs[x])
}
// some separation between iteration output
fmt.Println()
}
}
// just an input selector for testing
func inputSelector(expectedType reflect.Type) interface{} {
if reflect.ValueOf("hello selector").Type().ConvertibleTo(expectedType) {
return "hello selector"
}
if reflect.ValueOf(12345).Type().ConvertibleTo(expectedType) {
return 12345
}
if reflect.ValueOf(true).Type().ConvertibleTo(expectedType) {
return true
}
if reflect.ValueOf(3.14159).Type().ConvertibleTo(expectedType) {
return 3.14159
}
if reflect.ValueOf(sharedstuff).Type().ConvertibleTo(expectedType) {
return sharedstuff
}
// if the expectedType is a pointer we need to reflect new on it's contents
if expectedType.Kind() == reflect.Ptr {
return reflect.New(expectedType.Elem()).Interface()
}
// fallback to reflecting new on the expectedType and passing back it's interface
return reflect.New(expectedType).Interface()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment