I'm trying to dynamically call functions returning different types of struct
.
For example, let's take the following code.
struct A {
Name string
Value int
}
struct B {
Name1 string
Name2 string
Value float
}
func doA() (A) {
// some code returning A
}
func doB() (B) {
// some code returning B
}
I would like to pass either the function doA
or doB
as an argument to a generic function that would execute the function and JSON-encode the result. Like the following:
func Generic(w io.Writer, fn func() (interface {}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
But when I do:
Generic(w, doA)
I get the following error:
cannot use doA (type func() (A)) as type func() (interface {})
Is there a way to achieve this dynamic call?
First, let me remark that func() (interface{})
means the same thing as func() interface{}
, so I'll use the shorter form.
func() interface{}
You can write a generic function that takes a func() interface{}
argument as long as the function that you pass to it has type func() interface{}
, like this:
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() interface{} {
return &A{"Cats", 10}
}
func doB() interface{} {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn func() interface{}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
You can try out this code in a live playground:
http://play.golang.org/p/JJeww9zNhE
interface{}
If you want to write functions doA
and doB
that return concretely typed values, you can pass the chosen function as an argument of type interface{}
. Then you can use the reflect
package to make a func() interface{}
at run-time:
func Generic(w io.Writer, f interface{}) {
fnValue := reflect.ValueOf(f) // Make a concrete value.
arguments := []reflect.Value{} // Make an empty argument list.
fnResults := fnValue.Call(arguments) // Assume we have a function. Call it.
result := fnResults[0].Interface() // Get the first result as interface{}.
json.NewEncoder(w).Encode(result) // JSON-encode the result.
}
More concisely:
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
Complete program:
package main
import (
"encoding/json"
"io"
"os"
"reflect"
)
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() *A {
return &A{"Cats", 10}
}
func doB() *B {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
func main() {
Generic(os.Stdout, doA)
Generic(os.Stdout, doB)
}
Live playground:
http://play.golang.org/p/9M5Gr2HDRN
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With