How do I call a method by string variable? - go

I've seen this asked here before. But I don't understand the answers.
How do I call a method from a string value. So if the
I have many methods that are
func (c *something) whateverName(whatever map[string]interface{}) {
}
Same argument type in each one. no returns etc... Literally the only difference in the method name.
I'm looking to do something like this, and I just can't get it to work. I just want to call the correct method from the value of "var myMethod string":
func (c something) foo(m map[string]interface{}) {
fmt.Println("foo..")
//do something with m
}
func main() {
myMethod := "foo"
message := make(map[string]interface{})
//fill message with stuff...
c := something{} //this is just a hypothetical example...
vt := reflect.ValueOf(c)
vm := vt.MethodByName(myMethod)
vm.Call([]reflect.Value{reflect.ValueOf(message)})
}
I'm obviously not understanding how reflection works.

Your example works if you export the method. Change foo to Foo:
type something struct{}
func (c something) Foo(m map[string]interface{}) {
fmt.Println("Foo..")
//do something with m
}
func main() {
myMethod := "Foo"
message := make(map[string]interface{})
//fill message with stuff...
c := something{} //this is just a hypothetical example...
vt := reflect.ValueOf(c)
vm := vt.MethodByName(myMethod)
vm.Call([]reflect.Value{reflect.ValueOf(message)})
}
This will output (try it on the Go Playground):
Foo..
Also note that in this example Foo() has value receiver: c something. If the method has a pointer receiver such as c *something, you need to have a pointer value to start with, because a method with a pointer receiver is not in the method set of the non-pointer type.
See related: Call functions with special prefix/suffix

Related

Why can not use Pointer() method when reflect.Value is passed to an interface in golang?

I am writing a unit test to check equality of struct that contains func.
Here are my test code.
Go Palyround
When comparing, I used a func named GetFunctionName to get function's name for going.
func GetFunctionName(i interface{}) string {
fmt.Printf("type in GetFunctionName: %v\n", reflect.TypeOf(reflect.ValueOf(i)))
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
Also a compare function was made.
func SelectCompareStruct(got interface{}, want interface{}) {
rvGot := reflect.ValueOf(got)
rtGot := rvGot.Type()
rvWant := reflect.ValueOf(want)
rtWant := rvWant.Type()
for i := 0; i < rtGot.NumField(); i++ {
fieldGot := rtGot.Field(i)
fieldWant := rtWant.Field(i)
valueGot := rvGot.FieldByName(fieldGot.Name)
valueWant := rvWant.FieldByName(fieldWant.Name)
fmt.Printf("type in SelectCompareStruct: %v\n", reflect.TypeOf(reflect.ValueOf(valueGot)))
// Works
gotFuncNameInner := runtime.FuncForPC(valueGot.Pointer()).Name()
wantFuncNameInner := runtime.FuncForPC(valueWant.Pointer()).Name()
fmt.Printf("gotFuncNameInner:\n\t\t\t%v\nwantFuncNameInner:\n\t\t\t%v\n", gotFuncNameInner, wantFuncNameInner)
// Does not work
gotFuncName := GetFunctionName(valueGot)
wantFuncName := GetFunctionName(valueWant)
fmt.Printf("gotFuncName:\n\t%v\n wantFuncName:\n\t%v\n", gotFuncName, wantFuncName)
}
}
You can see, when I write directly to get function's name, it works.
However, it does not work when using a func instead.
Although, both of which type that apply Pointer() method are reflect.Value type.
Yes, I can change input type of GetFunctionName to reflect.Value for working.
That's not good for other use cases. I want to make a function for getting name for versatility.
It will be beautiful to make input type interface{}.
Anyone have any idea why? And how to fix it?
The problem is that you are calling reflect.Value on a reflect.Value. Fix by removing the extra call to reflect.Value.
func GetFunctionName(v reflect.Value) string {
fmt.Printf("type in GetFunctionName: %v\n", v.Type())
return runtime.FuncForPC(v.Pointer()).Name()
}
Run it on the playground.

invoke a method from a new instance (reflect.New) with reflection

I want to instantiate an object in Go using reflection and call a method on it. However, I have no idea how to do this. I have tried something, but it does not work.
type foo struct {
name string
}
func (f *foo) Bar() {
f.name = "baz"
fmt.Println("hi " + f.name)
}
func main() {
t := reflect.TypeOf(&foo{})
fooElement := reflect.New(t).Elem()
fooElement.MethodByName("Bar").Call([]reflect.Value{})
}
reflect.New works exactly like the new function, in that it returns an allocated pointer to the given type. This means you want pass the struct, not a pointer to the struct, to reflect.TypeOf.
t := reflect.TypeOf(foo{})
fooV := reflect.New(t)
Since you now have a pointer value of the correct type, you can call the method directly:
fooV.MethodByName("Bar").Call(nil)
https://play.golang.org/p/Aehrls4A8xB

Go Reflect field name to specific interface

I have a struct type with a number of fields that all implement a Renderer interface. The field types implement the interface with pointer receivers. I would like to have a function that takes the field name and calls the Render method on that field. I am able to locate the field and get lots of information about it, but doing the type assertion seems to be biting me because of the pointer receivers. Here's some code that shows my problem:
package main
import (
"fmt"
"reflect"
)
type Renderer interface {
Render()
}
type First struct {
ExampleField Field
}
type Field []int
func (f *Field) Render() {
fmt.Println("Hello from first")
}
func main() {
f := First{
Field{1, 2, 3},
}
f.ExampleField.Render()
renderField("ExampleField", &f)
renderField2("ExampleField", &f)
}
func renderField(field string, f *First) {
structVal := reflect.ValueOf(*f)
renderType := reflect.TypeOf((*Renderer)(nil)).Elem()
fieldToRender := structVal.FieldByName(field)
fieldPtr := reflect.PtrTo(fieldToRender.Type())
fmt.Printf("Implements? %v\n", fieldPtr.Implements(renderType))
fmt.Printf("Addressable? %v\n", fieldToRender.CanAddr())
fieldInter := fieldToRender.Interface()
if renderer, ok := fieldInter.(Renderer); ok {
// Pointer receiver so this never gets called
fmt.Print("Able to cast")
renderer.Render()
}
}
func renderField2(field string, f *First) {
structVal := reflect.ValueOf(*f)
fieldToRender := structVal.FieldByName(field)
vp := reflect.New(reflect.TypeOf(fieldToRender))
vp.Elem().Set(reflect.ValueOf(fieldToRender))
vpAddr := vp.Elem().Addr()
typeVal := vpAddr.Interface()
fmt.Println(typeVal) // <main.Field Value>⏎
renderer := typeVal.(Renderer)
renderer.Render()
// interface conversion: *reflect.Value is not main.Renderer: missing method Render
}
renderField2 seems to get me close but Addr() gives me a *Reflect.Value and when I call Interface() that seems to be the underlying type instead. If I switch to a non-pointer receiver then the first function works. I found reflect value Interface and pointer receiver which seems to be almost exactly what I'm asking, and the question is answered but if I actually call the isZeroer method presented in the playground link it's always false so it doesn't actually seem to answer the question.
It seems like Addr is the key because it specifically mentions pointer receivers but I'm struggling to coerce it back into an interface.
Use this code:
func renderField(name string, f *First) {
structVal := reflect.ValueOf(f).Elem()
field := structVal.FieldByName(name).Addr().Interface()
if renderer, ok := field.(Renderer); ok {
renderer.Render()
}
}
The key point is to change:
structVal := reflect.ValueOf(*f)
to:
structVal := reflect.ValueOf(f).Elem()
The statement used in the question creates a non-addressable struct value. The fields in a non-addressable struct are also not addressable, therefore it's not possible to access the pointer receiver on the fields.
The statement used in this answer creates an addressable struct value.

Function types in Go - particular type casting to more general type

What cast / assertion need I do in Go in order to pass to a function expecting a generic function like func(interface{}) interface{}, a more specific function like func(int) int instead?
For example, in code like this, fooA can be passed to MakeExclamer, but not fooB:
func MakeExclamer(foo func (interface{}) interface{}, n int) func () {
return func() {
fmt.Printf("%v!!!", foo(n))
}
}
func fooA(x interface{}) interface{} {
return x.(int)*2
}
func fooB(x int) int {
return x * 10
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
// >> cannot use fooB (type func(int) int) as type func(interface {}) interface {} in argument to MakeExclamer
exclamerB()
}
(Go Playground link: https://play.golang.org/p/xGzfco0IAG)
I'm not interested much in alternative code structure patterns, since this is how I want it to work: a specific function should be passed to a general function transformer (accepting function of type Any -> Any) that will return another general function (Any -> Any). This may not be idiomatic in Go, but it is the pattern that I want my code to follow.
To use type assertions, every possible type must be enumerated in MakeExclamer:
func MakeExclamer(fn interface{}, arg interface{}) func() {
switch fn := fn.(type) {
case func(int) int:
return func() {
fmt.Printf("%v!!!\n", fn(arg.(int)))
}
case func(interface{}) interface{}:
return func() {
fmt.Printf("%v!!!\n", fn(arg))
}
default:
panic("not supported")
}
}
To accept a function of any type, the fn argument is declared as type interface{}. The code uses a type switch to handle the different function types.
playground example
Reflection can be used to write a more general function.
func MakeExclamer(fn interface{}, arg interface{}) func() {
fnr := reflect.ValueOf(fn)
argr := reflect.ValueOf(arg)
return func() {
resultr := fnr.Call([]reflect.Value{argr})
fmt.Printf("%v!!!\n", resultr[0].Interface())
}
}
playground example
First things first : When it comes to typing in Go, everything is theoretically possible. That's because even though the compiler does a lot of checks at compile-time, it is possible to change the runtime... at runtime. So-called runtime hacks, where you dynamically manipulate runtime structs that you're NOT supposed to handle.
Now, you have an interesting question, whose answer doesn't include the need to use the 'unsafe' package. However, the way I found of generalizing a function involves heavy reflection.
How to call a function (via reflection) ?
The documentation for the reflect package can be found here.
So, like all elements in Golang, functions have a Type. Without going through all fields, functions do take an array of arguments and produce an array of results. It is possible to investigate the Type of arguments and results through the In(int) and Out(int) method.
func investigate(fn interface{}) {
fnType := reflect.TypeOf(fn)
for idx := 0; idx < fnType.NumIn(); idx ++ {
fmt.Printf("Input arg %d has type %v\n", idx, fnType.In(idx))
}
for idx := 0; idx < fnType.NumOut(); idx ++ {
fmt.Printf("Output arg %d has type %v\n", idx, fnType.Out(idx))
}
}
We won't use this code. However, two important things are to be noted at this point :
The generic type under which a function can be passed around without caring about its type is interface{}. Something like "func(interface{}) interface{}" is not a generalization of a function, it is already a concrete type. Hence, "func(interface{}) interface{}" is not a generalization of "func(int) int", those are two different function types entirely. This is why you can't use type assertions/cast to convert from one function type to another.
A function can be represented as something that takes an input array and produces and output array.
Now, in order to call a function, you have to get not its Type, but its Value. Once you get its value, you can call it using an array of arguments, which must all be Values.
The prototype is:
func (v Value) Call(in []Value) []Value
Using this method, it is possible to call any function.
The code
So, the only thing you need is to convert whichever arguments array you have to an array of Values, then you will be able to call your function.
Here is your code:
package main
import (
"fmt"
"reflect"
)
func MakeExclamer(foo interface{}, n int) func() {
exclamer := generalize(foo, n)
return func() {
fmt.Printf("%v!!!\n", exclamer())
}
}
func fooA(x interface{}) interface{} {
return x.(int) * 2
}
func fooB(x int) int {
return x * 10
}
func generalize(implem interface{}, args ...interface{}) func() interface{} {
valIn := make([]reflect.Value, len(args), len(args))
fnVal := reflect.ValueOf(implem)
for idx, elt := range args {
valIn[idx] = reflect.ValueOf(elt)
}
ret := func() interface{} {
res := fnVal.Call(valIn)
// We assume the function produces exactly one result
return res[0].Interface()
}
return ret
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
exclamerB()
}
Playground
The important bit is the generalize function which makes the translation between your arguments and an array of Values, then returns a new function whith all parameters already filled.
Do not hesitate if you need any precision !

Map of methods in Go

I have several methods that I'm calling for some cases (like Add, Delete, etc..). However over time the number of cases is increasing and my switch-case is getting longer. So I thought I'd create a map of methods, like Go map of functions; here the mapping of functions is trivial. However, is it possible to create a map of methods in Go?
When we have a method:
func (f *Foo) Add(a string, b int) { }
The syntax below create compile-time error:
actions := map[string]func(a, b){
"add": f.Add(a,b),
}
Is it possible to create a map of methods in Go?
Yes. Currently:
actions := map[string]func(a string, b int){
"add": func(a string, b int) { f.Add(a, b) },
}
Later: see the go11func document guelfi mentioned.
There is currently no way to store both receiver and method in a single value (unless you store it in a struct). This is currently worked on and it may change with Go 1.1 (see http://golang.org/s/go11func).
You may, however, assign a method to a function value (without a receiver) and pass the receiver to the value later:
package main
import "fmt"
type Foo struct {
n int
}
func (f *Foo) Bar(m int) int {
return f.n + m
}
func main() {
foo := &Foo{2}
f := (*Foo).Bar
fmt.Printf("%T\n", f)
fmt.Println(f(foo, 42))
}
This value can be stored in a map like anything else.
I met with a similar question.
How can this be done today, 9 years later:
the thing is that the receiver must be passed to the method map as the first argument. Which is pretty unusual.
package main
import (
"fmt"
"log"
)
type mType struct {
str string
}
func (m *mType) getStr(s string) {
fmt.Println(s)
fmt.Println(m.str)
}
var (
testmap = make(map[string]func(m *mType, s string))
)
func main() {
test := &mType{
str: "Internal string",
}
testmap["GetSTR"] = (*mType).getStr
method, ok := testmap["GetSTR"]
if !ok {
log.Fatal("something goes wrong")
}
method(test, "External string")
}
https://go.dev/play/p/yy3aR_kMzHP
You can do this using Method Expressions:
https://golang.org/ref/spec#Method_expressions
However, this makes the function take the receiver as a first argument:
actions := map[string]func(Foo, string, int){
"add": Foo.Add
}
Similarly, you can get a function with the signature func(*Foo, string, int) using (*Foo).Add
If you want to use pointer to type Foo as receiver, like in:
func (f *Foo) Add(a string, b int) { }
then you can map string to function of (*Foo, string, int), like this:
var operations = map[string]func(*Foo, string, int){
"add": (*Foo).Add,
"delete": (*Foo).Delete,
}
Then you would use it as:
var foo Foo = ...
var op string = GetOp() // "add", "delete", ...
operations[op](&foo, a, b)
where GetOp() returns an operation as string, for example from a user input.
a and b are your string and int arguments to methods.
This assumes that all methods have the same signatures. They can also have return value(s), again of the same type(s).
It is also possible to do this with Foo as receiver instead of *Foo. In that case we don't have to de-reference it in the map, and we pass foo instead of &foo.

Resources