Calling a method with Go Reflect by name and with a parameter - go

This is a follow on from Calling a function with Go Reflect .
To simplify the question I cut out what I could, hard coded some values and ~hopefully~ didn't make it unclear in the process. I'm getting an error on the code "method.Call(env)" near the bottom.
Ideally what I would like to do is minimize the use of reflection similarly how ThunderCat did on the previous question with the line:
method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)
but if that's not possible the simplest way it can be done would be perfectly fine. If this seems like a basic question, my apologies, I am very new to Go.
The error I am getting is:
cannot use env (type Environment) as type []reflect.Value in argument to method.Call
which is because I would like to assert the method to the function with the correct signature as was done on the previous quesiton but after quite a bit of playing around I just haven't quite got it.
The simplified code:
package main
import (
"flag"
"fmt"
"reflect"
)
type CommandLineFlags struct {
Debug *bool
}
type Environment struct {
CLF CommandLineFlags
}
type ModuleInfo struct {
Initialize bool // Flag: True of module has Initialization function and it should be called. Default: false
Module string // Name of the module. No need to hard code, will be set during initialization.
}
type ModuleInit struct{}
func main() {
var env Environment
env.CLF.Debug = flag.Bool("dbg", false, "Enables Debug Messages")
flag.Parse()
modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "logger"
miValue := reflect.ValueOf(ModuleInit{})
// miType := reflect.TypeOf(ModuleInit{})
for _, m := range modules {
if m.Initialize {
funcName := m.Module + "Init"
method := miValue.MethodByName(funcName)
fmt.Println(funcName)
// Would like to do something like this
// ...Func.Interface().(func(core.ModuleInit) core.ModuleInit)
// like is done with the referenced quesiton above so as to minimize the use of reflect calls.
method.Call(env)
}
}
}
func (mi ModuleInit) LoggerInit(env *Environment) {
var debugEnabled = *env.CLF.Debug
// ...and more stuff.
}

The method has the type func(*Environment). Assert to that type and call:
modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "Logger"
miValue := reflect.ValueOf(ModuleInit{})
for _, m := range modules {
if m.Initialize {
funcName := m.Module + "Init"
method := miValue.MethodByName(funcName).Interface().(func(*Environment))
method(&env)
}
}
Run it on the Playground.
(Note two issues fixed: The module should be "Logger", not "logger", method takes a *Environment, not an Environment.)
The code above will panic if the method is not found or does not have the correct type. Here's the code with checks to prevent a panic:
modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "Logger"
miValue := reflect.ValueOf(ModuleInit{})
for _, m := range modules {
if m.Initialize {
funcName := m.Module + "Init"
method := miValue.MethodByName(funcName)
if !method.IsValid() {
fmt.Printf("method %s not found", funcName)
continue
}
fn, ok := method.Interface().(func(*Environment))
if !ok {
fmt.Println("method is not func(*Environment)")
continue
}
fn(&env)
}
}
Run it on the Playground.

There is several errors in OP code,
the func name was not properly generated,
the reflected method instance was not properly checked for validity,
env parameter of LoggerInit was a pointer, a value was sent in,
method call was not properly done.
Here is the fixed version (https://play.golang.org/p/FIEc6bTvGWJ).
package main
import (
"flag"
"fmt"
"log"
"reflect"
"strings"
)
type CommandLineFlags struct {
Debug *bool
}
type Environment struct {
CLF CommandLineFlags
}
type ModuleInfo struct {
Initialize bool // Flag: True of module has Initialization function and it should be called. Default: false
Module string // Name of the module. No need to hard code, will be set during initialization.
}
type ModuleInit struct{}
func main() {
var env Environment
env.CLF.Debug = flag.Bool("dbg", false, "Enables Debug Messages")
flag.Parse()
modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "logger"
miValue := reflect.ValueOf(ModuleInit{})
// miType := reflect.TypeOf(ModuleInit{})
for _, m := range modules {
if m.Initialize {
funcName := strings.Title(m.Module) + "Init"
method := miValue.MethodByName(funcName)
log.Printf("%#v %v\n", method, funcName)
if !method.IsValid() || method.IsNil() {
break
}
fmt.Println(funcName)
// Would like to do something like this
// ...Func.Interface().(func(core.ModuleInit) core.ModuleInit)
// like is done with the referenced quesiton above so as to minimize the use of reflect calls.
out := method.Call([]reflect.Value{reflect.ValueOf(env)})
fmt.Println(out) // A bunch of relfect.Values.
}
}
}
func (mi ModuleInit) LoggerInit(env Environment) {
var debugEnabled = *env.CLF.Debug
// ...and more stuff.
log.Println("LoggerInit ", debugEnabled)
}

The issue is that the argument passed reflect.Value.Call needs to be of the type reflect.Value itself. See the signature from https://golang.org/pkg/reflect/#Value.Call
func (v Value) Call(in []Value) []Value

You must wrap the env variable in a []reflect.Value since reflect.Value.Call requires a slice of reflect.Value.
args := []reflect.Value{reflect.ValueOf(&env),}
method.Call(args)
Also, some typos in your code:
modules[0].Module = "Logger"

Related

Can I mock a function with pointer parameter which need to be used

Let's say we have a library provide a function Double to double the integer, we use pointer i to get the result value not by return:
package api
type Action interface {
Double(i *int) error
}
type NUM struct{}
func (n NUM) Double(i *int) error {
*i *= 2
return nil
}
in our main function we use this library to do our task. like this:
package app
import (
"fmt"
"github.com/hotsnow/api"
)
func main() {
j := job{a: &api.NUM{}}
d := j.task(3)
fmt.Println(3, d)
}
type job struct {
a api.Action
}
// double me
func (j job) task(i int) int {
j.a.Double(&i)
return i
}
Now we need to test the task() function, how can we get the pointer return bye mock the Double function?
Here is the test:
package app
import (
"github.com/golang/mock/gomock"
"github.com/hotsnow/mocks"
"testing"
)
func TestReq(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := mocks.NewMockAction(ctrl)
m.EXPECT().Double(gomock.Any()).Return(nil)
j := job{a: m}
got := j.task(3)
if got != 6 {
t.Errorf("got = %#v; want 6", got)
}
}
The code here: https://github.com/hotsnow/mock.git (stackoverflow branch)
you can use gomock setarg function for this
yourPackage.EXPECT().insert(&pointer).SetArg(0, newPointer)
You can achieve this with the provided Eq() matcher, which internally calls reflect.DeepEqual() on the expected and actual values; as per the documentation for this method:
Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.
Say we have a function that depends upon an interface method that takes a pointer parameter:
package resource
type ServiceRequest struct {
Name string
Owner *string // this is a pointer so it can be omitted with `nil`
}
type Model struct {
// resource model...
}
type ResourceService interface {
Fetch(req *ServiceRequest) (Model, error)
}
type getResourceHandler struct {
resourceService ResourceService
}
type GetResourceEvent struct {
Resource string
Owner *string
}
func NewResourceHandler(resourceService ResourceService) *getResourceHandler {
return &getResourceHandler{resourceService}
}
func (h *getResourceHandler) Handle(event GetResourceEvent) (Model, error) {
return h.resourceService.Fetch(&ServiceRequest{event.Resource, event.Owner})
}
We can use the Eq() matcher when setting up the expectation against our generated mock of the ResourceService interface:
package test
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/org/repo/internal/mock"
"github.com/org/repo/internal/resource"
)
func optionalString(str string) *string {
return &str
}
func Test_GetResourceHandler_ReturnsResultFromService(t *testing.T) {
resourceName := "my-resource"
owner := optionalString("Joe Bloggs")
resourceReq := &resource.ServiceRequest{resourceName, owner}
event := resource.GetResourceEvent{resourceName, owner}
model := resource.Model{ /* fields here... */ }
ctrl := gomock.NewController(t)
mockResourceService := mock.NewMockResourceService(ctrl)
handler := resource.NewResourceHandler(mockResourceService)
mockResourceService.EXPECT().Fetch(gomock.Eq(resourceReq)).Return(model, nil)
res, err := handler.Handle(event)
assert.Nil(t, err)
assert.Equal(t, model, res)
}
If you change the contents of the service request in either the test or the unit under test, you'll see that the test no longer passes. Otherwise, it will pass in spite of the test and the unit under test having their own respective pointers to separate ServiceRequest{} values.
It seems you don't have to use gomock to test the task method.
Since you have an interface, why not just create a mock implementation of the interface, for example:
type dummy struct{
callCount int
}
func (d *dummy) Double(i *int) error {
d.callCount++
return nil
}
d := dummy{}
j := job{a: &d}
got := j.task(3)
if d.callCount != 1 {
// XXX
}

Casting a string to a func type in GoLang

I have a string which is the name of a function in GoLang.
I want to treat them as function. How should I do this? I tried to achieve it through reflect.* but I didn't find a valid path for my purpose.
I get the name fo handlers in a JSON file, and I want to execute those handlers. Something like this:
{
"students/show" : "ShowStudents",
"students/add" : "AddStudents"
}
Then I want to execute ShowStudents(), but don't know how to treat it like a variable of type func
Your task can be broken down into two steps:
Extract function names
Run those functions (assuming that they are defined somewhere)
For step 1, I would unmarshal the JSON into a map[string]string, something like this:
b, err := ioutil.ReadFile(fname)
mp := make(map[string]string)
json.Unmarshal(b, &mp)
Coming to Step 2. In Go, it's not possible to convert string directly to a function call, but it is possible to enumerate the methods of an object using reflect package. This can be used as a workaround in this case. Instead of writing those functions directly, bind them to a dummy type, something like this:
type T int
func (t T) ShowStudents() {
fmt.Println("Showing Students")
}
func (t T) AddStudents() {
fmt.Println("Adding Students")
}
func main() {
var t T
reflect.ValueOf(t).MethodByName("ShowStudents").Call(nil)
}
Run this example
establish a mapping between the keys in the json file and the functions, then use that to call the functions as they appear in the json
package main
import (
"encoding/json"
"fmt"
)
func AddStudents() {
fmt.Println("woo")
}
func ShowStudents() {
fmt.Println("lots of students")
}
func main() {
js := `{
"students/show" : "ShowStudents",
"students/add" : "AddStudents"
}`
lookup := make(map[string]string)
json.Unmarshal([]byte(js), &lookup)
dispatch := make(map[string]func())
dispatch["students/show"] = ShowStudents
dispatch["students/add"] = AddStudents
for v, _ := range lookup {
print(v)
dispatch[v]()
}
}

Plugin symbol as function return

I'm running into a Go behaviour which I don't understand. My idea is to import a plugin which implements an interface that is out of both packages. If a struct is returned it works fine, but to be sure it implements the interface, I want to return an interface which fails.
Interface definition:
package iface
type IPlugin interface{
SayHello(string)
SayGoodby(string)
WhatsYourName() string
}
The main program looks like this:
package main
import (
"plugin"
"plugin_test/iface"
"errors"
"fmt"
)
//go:generate go build -buildmode=plugin -o ./pg/test.so ./pg/test.go
func main(){
path := "pg/test.so"
plug, err := plugin.Open(path)
if err != nil {
panic(err)
}
sym, err := plug.Lookup("Greeter")
if err != nil {
panic(err)
}
var pg iface.IPlugin
pg, ok := sym.(iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
fmt.Printf("You're now connected to: %s \n", pg.WhatsYourName())
pg.SayHello("user")
pg.SayGoodby("user")
}
The plugin (stored in pg/test.go)
package main
import (
"fmt"
"plugin_test/iface"
)
type testpl struct {}
func(pl testpl) SayHello(s string){
fmt.Printf("Plugin says hello to %s \n", s)
}
func(pl testpl) SayGoodby(s string){
fmt.Printf("Plugin says goodby to %s \n", s)
}
func(pl testpl) WhatsYourName() string{
return "my name is Test-Plugin"
}
/* This function works */
func getPlugin() testpl{
return testpl{}
}
/* This function doesn't work */
func getPlugin() iface.IPlugin{
return testpl{}
}
/* This function also doesn't work */
func getPlugin() interface{}{
return testpl{}
}
var Greeter = getPlugin()
I tried every getPlugin function on its own.
The function returning testpl prints the expected output:
You're now connected to: my name is Test-Plugin
Plugin says hello to user
Plugin says goodby to user
The other functions end on sym.(iface.IPlugin)
panic: error binding plugin to interface
goroutine 1 [running]:
main.main()
/home/../../../main.go:27 +0x343
exit status 2
Can someone explain why this isn't possible? Wouldn't it be easier to create a plugin if it did't let you build your plugin in such a case?
What you want is possible, but there is something in the background that prevents it from working.
This is namely that you want to lookup a variable named Greeter from the plugin. Plugin.Lookup() will return a pointer to this variable! If it wouldn't, you could only inspect its value, but you couldn't change it.
You can verify this by simply printing the type of the value stored in sym:
fmt.Printf("%T\n", sym)
In your first case func getPlugin() testpl, output will be:
*main.testpl
In your second case func getPlugin() iface.IPlugin, output will be:
*iface.IPlugin
(Yes, it's a pointer to an interface!)
In your third case func getPlugin() interface{}, output will be:
*interface {}
So your first example works because the value stored in sym is of type *main.testpl, which also implements iface.IPlugin (because main.testpl implements it, so does the pointer type).
Back to your 2nd example: func getPlugin() iface.IPlugin
The value stored in sym is of type *iface.IPlugin. A value of pointer type to interface never satisfies any interfaces (except the empty interface), so attempting to type-assert iface.IPlugin from a value of type *iface.IPlugin will never succeed. You have to type assert *iface.IPlugin type, which you can dereference after to obtain a value of type iface.IPlugin. It could look like this:
pgPtr, ok := sym.(*iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
pg := *pgPtr
And now everything works as expected!
To avoid such hassle and confusion, you may implement your plugin to expose a function which returns you the Greeter:
func Greeter() iface.IPlugin { return testpl{} }
And then get rid of the Greeter global var of course. If you do this, you may lookup the Greeter symbol which will be of type:
func() iface.IPlugin
The difference is that looking up a function does not require the plugin package to return a pointer to the value, while in case of a variable it does. A simple function type, no pointer-to-interface-kung-fu. Using it to obtain the greeter would be:
Greeter, err := p.Lookup("Greeter")
if err != nil {
panic(err)
}
greeterFunc, ok := GetFilter.(func() iface.IPlugin)
if !ok {
panic(errors.New("not of expected type"))
}
greeter := greeterFunc()
// And using it:
fmt.Printf("You're now connected to: %s \n", greeter.WhatsYourName())
greeter.SayHello("user")
greeter.SayGoodby("user")
See related / similar question: go 1.8 plugin use custom interface

TypeOf without an instance and passing result to a func

Is it possible in go to get a "Type" without an instance? I've seen some examples that utilize reflect.TypeOf() but they all deal with an instance.
Below is a snippet of what I am attempting to do:
import (
"net/http"
)
type ParamReader struct {
// The request from which to extract parameters
context *http.Request
}
// Initialize the ParamReader with a specific http request. This serves
// as the 'context' of our param reader. All subsequent calls will validate
// the params that are present on this assigned http.Request
func (p *ParamReader) Context(r *http.Request) {
p.context = r
}
// Validate that a given param 's' is both present and a valid
// value of type 't'. A value is demeed valid if a conversion from
// its string representation to 't' is possible
func(p *ParamReader) Require(s string, t Type) {
// if context not have 's'
// addError('s' is not present)
// return
if( t == typeof(uint64)) {
// If not s -> uint64
// addError('s' is not a valid uint64)
} else if (t == typeof(uint32)) {
// ....
} / ....
}
An example of my usage would be
func (h *Handler) OnRequest(r *http.Request) {
h.ParamReader.Context(r)
h.ParamReader.Require("age", uint16)
h.ParamReader.Require("name", string)
h.ParamReader.Require("coolfactor", uint64)
h.ParamReader.Optional("email", string, "unspecified")
h.ParamReader.Optional("money", uint64, "0")
if h.ParamReader.HasErrors() {
// Iterate or do something about the errors
} else {
coolness := h.ParamReader.ReadUint64("coolfactor")
email := h.ParamReader.ReadString("email")
money := h.ParamReader.ReadUint64(0)
}
}
Note, after writing this out, I realize I could provide a "RequireUint64", "RequireUint32", etc.. perhaps that would be the Go way?
Yes, it's possible. The trick is to start from a pointer to the type (whose value can be a typed nil, that's perfectly OK), and then use Type.Elem() to get the reflect.Type descriptor of the pointed type (the base type).
See some examples:
t := reflect.TypeOf((*int)(nil)).Elem()
fmt.Println(t)
t = reflect.TypeOf((*http.Request)(nil)).Elem()
fmt.Println(t)
t = reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(t)
Output (try it on the Go Playground):
int
http.Request
os.File
See related questions:
Golang reflect: Get Type representation from name?
How to get the string representation of a type?
If you want to pass around the types and use them in switches, you can create and store them in global variables once like this, and refer to the global vars:
var (
intType = reflect.TypeOf((*int)(nil))
httpRequestType = reflect.TypeOf((*http.Request)(nil))
osFileType = reflect.TypeOf((*os.File)(nil))
int64Type = reflect.TypeOf((*uint64)(nil))
)
func printType(t reflect.Type) {
switch t {
case intType:
fmt.Println("Type: int")
case httpRequestType:
fmt.Println("Type: http.request")
case osFileType:
fmt.Println("Type: os.file")
case int64Type:
fmt.Println("Type: uint64")
default:
fmt.Println("Type: Other")
}
}
func main() {
printType(intType)
printType(httpRequestType)
printType(osFileType)
printType(int64Type)
}
Output of the above (try it on the Go Playground):
Type: int
Type: http.request
Type: os.file
Type: uint64
But honestly, if you're using it like this way and you're not using reflect.Type's methods, then creating constants is much easier and more efficient. It could look like this:
type TypeDesc int
const (
typeInt TypeDesc = iota
typeHttpRequest
typeOsFile
typeInt64
)
func printType(t TypeDesc) {
switch t {
case typeInt:
fmt.Println("Type: int")
case typeHttpRequest:
fmt.Println("Type: http.request")
case typeOsFile:
fmt.Println("Type: os.file")
case typeInt64:
fmt.Println("Type: uint64")
default:
fmt.Println("Type: Other")
}
}
func main() {
printType(typeInt)
printType(typeHttpRequest)
printType(typeOsFile)
printType(typeInt64)
}
Output is the same. Try it on the Go Playground.
I'm fairly certain this isn't possible in Go. While it's far from ideal you can use Type.Name() and a string as the functions arg to do whatever comparisons are necessary.
package main
import (
"fmt"
"reflect"
)
func main() {
printIt("int")
}
func printIt(x string) {
i := 10
if (reflect.TypeOf(i).Name() == x) {
fmt.Println(x)
}
}

How To Call Method of another package from string method name in Go

Suppose I have two package like
-a
-b
a have some methods like this
func TestOne() { //something }
func TestTwo() { //something }
I need to call package a's methods from package b but by only string method name. Like i get the string "TestOne" and calls for the method TestOne(). How can i get that done.
Edit :
I have Read about reflect. but reflect needs an struct and functions be a member of that struct. What if My functions are not member of a struct? just plain methods in a package. and the calling methods and called methods are in different package. Then?
NB. There could be some methods that have parameters as well.
Like LightWeight said in his answer, you can use reflection.
You use the reflect.ValueOf method to get the value of the type. Then you can use the MethodByName method to get the function value. Once you have the function value you can call the Call method to execute it.
Code Sample
package main
import (
"fmt"
"reflect"
)
type TypeOne struct {
}
func (t *TypeOne) FuncOne() {
fmt.Println("FuncOne")
}
func (t *TypeOne) FuncTwo(name string) {
fmt.Println("Hello", name)
}
func CallFuncByName(myClass interface{}, funcName string, params ...interface{}) (out []reflect.Value, err error) {
myClassValue := reflect.ValueOf(myClass)
m := myClassValue.MethodByName(funcName)
if !m.IsValid() {
return make([]reflect.Value, 0), fmt.Errorf("Method not found \"%s\"", funcName)
}
in := make([]reflect.Value, len(params))
for i, param := range params {
in[i] = reflect.ValueOf(param)
}
out = m.Call(in)
return
}
func main() {
t1 := &TypeOne{}
out, err := CallFuncByName(t1, "FuncOne")
if err != nil {
panic(err)
}
//Return value
_ = out
out, err = CallFuncByName(t1, "FuncTwo", "monkey")
if err != nil {
panic(err)
}
//Return value
_ = out
}
You can try to use reflect in go. This link may be help you
https://golang.org/pkg/reflect/
and http://mikespook.com/2012/07/function-call-by-name-in-golang/
func foo() {
// bla...bla...bla...
}
func bar(a, b, c int) {
// bla...bla...bla...
}
funcs := map[string]interface{}{"foo":foo, "bar":bar}

Resources