How to pass parameters to decorated functions? - go

I would like to write a decorator to wrap a function with "before" and "after" commands. A first version is below, where the decorated function just outputs hello:
package main
import "fmt"
func main() {
wrapper(printHello, "world")
}
func wrapper(f func(), who string) {
fmt.Printf("before function, sending %v\n", who)
f()
fmt.Print("after function\n")
}
func printHello() {
fmt.Printf("hello\n")
}
(Playground: https://play.golang.org/p/vJuQKWpZ2h9)
I now would like to call the decorated function with a parameter (in my case "world"). In the example above, it is successfully passed to wrapper() but then I do not know what to do further. I thought that I would just
package main
import "fmt"
func main() {
wrapper(printHello, "world") // cannot use printHello as the type func()
}
func wrapper(f func(), who string) {
fmt.Printf("before function, sending %v\n", who)
f(who) // too many arguments
fmt.Print("after function\n")
}
func printHello(who string) {
fmt.Printf("hello %v\n", who)
}
The compilation failes with
.\scratch_11.go:6:9: cannot use printHello (type func(string)) as type func() in argument to wrapper
.\scratch_11.go:11:3: too many arguments in call to f
have (string)
want ()
What is the proper way to pass arguments to the decorated function?

You have to declare the correct variable type for this to work:
func wrapper(f func(string), who string) {
...

Related

Passing a function with parameters to time.AfterFunc

time.AfterFunc() accepts a duration and a function to be executed when that duration has expired. But the function cannot be a function that accepts parameters.
For example: The following function cannot be passed:
func Foo (b *Bar) {}
Although, it is possible to initialize a new function that calls the above one and then pass it:
f := func() {
Foo(somebar)
}
timer := time.AfterFunc(1*time.Second, f)
Should this really be done this way?
Why does time.AfterFunc not accept any functions that accept parameters?
Do there exist other/better ways to do this?
Create a function from the argument, return it.
package main
import (
"fmt"
"time"
)
func foo(bar string) {
fmt.Printf("in foo('%s')\n", bar)
}
func newFunc(bar string) func() {
fmt.Printf("creating func with '%s'\n", bar)
return func() {
foo(bar)
}
}
func main() {
somebar := "Here we go!"
f := newFunc(somebar)
_ = time.AfterFunc(1*time.Second, f)
time.Sleep(2 * time.Second)
}
https://play.golang.com/p/lWgeHvPLg9N
Anonymous function helps you to send functions with parameters to AfterFunc.
package main
import (
"fmt"
"time"
)
func foo(bar string) {
fmt.Printf("in foo('%s')\n", bar)
}
func main() {
somebar := "Here we go!"
time.AfterFunc(1*time.Second, func(){foo(somebar)})
time.Sleep(2 * time.Second)
}
https://play.golang.com/p/sdpiBtBWt_s

Call Method Expression with Pointer to Struct as Receiver

There is func someFunc(v interface{}, fn interface{}) where v is a pointer to struct (say *A) and fn is a method expression (say (*A).method()). How to call fn with v as parameter (using reflect)?
It's possible to do with reflect.Value.Call(), however it's pretty cumbersome, especially if you need to do something with the return value. But here's a basic example:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Bar string
}
func concrete(foo *Foo) {
fmt.Printf("Foo: %#v\n", foo)
}
func someFunc(v interface{}, fn interface{}) {
f := reflect.ValueOf(fn)
arg := reflect.ValueOf(v)
f.Call([]reflect.Value{arg})
}
func main() {
foo := Foo{"Bar"}
someFunc(&foo, concrete)
}
// Output: Foo: &main.Foo{Bar:"Bar"}
https://play.golang.org/p/ED6QdvENxti
If you want to call a method of a struct by name, we need to revise it just a bit:
type Foo struct {
Bar string
}
func (f *Foo) Concrete() {
fmt.Printf("Foo: %#v\n", f)
}
func callByName(v interface{}, fn string) {
arg := reflect.ValueOf(v)
f := arg.MethodByName(fn)
f.Call([]reflect.Value{})
}
func main() {
foo := Foo{"Bar"}
callByName(&foo, "Concrete")
}
Notice that in this case the method value is already bound to the struct instance, so we don't need to pass it anything as an argument.
So to the challenge of using reflect to call a method without knowing name and being a method of the same type, as op (orignally) addressed, I have come up with a very, very ugly and unsafe way.
package main
import (
"fmt"
"reflect"
"runtime"
"strings"
)
func getFName(v reflect.Value) string {
return runtime.FuncForPC(v.Pointer()).Name()
}
func callMethod(a,fn interface{}) {
fname:=getFName(reflect.ValueOf(fn))
parts:=strings.Split(fname,".")
name:=strings.TrimSuffix(parts[len(parts)-1],"-fm")
reflect.ValueOf(a).MethodByName(name).Call(nil)
}
func (s *a) Tst() {
fmt.Println(s)
}
type a struct { p string }
func main() {
x,y:=a{"Good"},a{"Bad"}
callMethod(&x,y.Tst)
}
Playground: https://play.golang.org/p/QgrGhI5DC3p
I would like to know a better way that does not rely on how runtime.FuncForPc formats methods (which is not version-safe), but this is the best I have. Please do tell me any ideas to improve it.

Passing in a type variable into function

I'm trying to achieve a type assertion by passing in a type into a function. In other words, I'm trying to achieve something like this:
// Note that this is pseudocode, because Type isn't the valid thing to use here
func myfunction(mystring string, mytype Type) {
...
someInterface := translate(mystring)
object, ok := someInterface.(mytype)
... // Do other stuff
}
func main() {
// What I want the function to be like
myfunction("hello world", map[string]string)
}
What's the proper function declaration I need to use in myfunction, to successfully perform the type assertion in myfunction?
#hlin117,
Hey, if I understood your question correctly and you need to compare the types, here's what you can do:
package main
import (
"fmt"
"reflect"
)
func myfunction(v interface{}, mytype interface{}) bool {
return reflect.TypeOf(v) == reflect.TypeOf(mytype)
}
func main() {
assertNoMatch := myfunction("hello world", map[string]string{})
fmt.Printf("%+v\n", assertNoMatch)
assertMatch := myfunction("hello world", "stringSample")
fmt.Printf("%+v\n", assertMatch)
}
The approach is to use a sample of the type you'd like to match.

Using callbacks and functions as a type in go

I am attempting to create a sort of function that is similar to the Express (NodeJS) route method in Go:
app.get("route/here/", func(req, res){
res.DoStuff()
});
In this example I want "foo" (the type) to be the same as the anonymous function in the above method. Here is one of my failed attempts using Go:
type foo func(string, string)
func bar(route string, io foo) {
log.Printf("I am inside of bar")
// run io, maybe io() or io(param, param)?
}
func main() {
bar("Hello", func(arg1, arg2) {
return arg + arg2
})
}
How might I fix my dilemma? Should I not use a type and use something else? What are my options?
You are on the right track - creating a type for a func in the context you are using it adds clearer design intent and additional type safety.
You just need to modify your example a bit for it to compile:
package main
import "log"
//the return type of the func is part of its overall type definition - specify string as it's return type to comply with example you have above
type foo func(string, string) string
func bar(route string, io foo) {
log.Printf("I am inside of bar")
response := io("param", "param")
log.Println(response)
}
func main() {
bar("Hello", func(arg1, arg2 string) string {
return arg1 + arg2
})
}
package main
import (
"fmt"
"log"
)
type foo func(string, string)
func bar(route string, callback foo) bool {
//...logic
/* you can return the callback to use the
parameters and also in the same way you
could verify the bar function
*/
callback("param", "param")
return true
}
func main() {
fmt.Println("Hello, playground")
res := bar("Hello", func(arg1, arg2 string) {
log.Println(arg1 + "_1")
log.Println(arg2 + "_2")
})
fmt.Println("bar func res: ", res)
}

Dynamic function call in Go

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.
Passing a function of type 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
Passing a function as an argument of type 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
Your return signature is different for these functions:
fn func() (interface {}) vs. func doA() (A) and func doB() (B)
You are getting a compiler error because you are passing a function with a different signature into your Generic function. To address this issue you can change your functions to return interface{}.
This is an example of how to do that, I am using anonymous structs and printing the return value out rather than serializing them but this applies just the same to your example:
package main
import "fmt"
func doA() interface{} {
return struct {
Name string
Value int
}{
"something",
5,
}
}
func doB() interface{} {
return struct {
Name1 string
Name2 string
Value float64
}{
"something",
"or other",
5.3,
}
}
func main() {
fmt.Println("Hello, playground", doA(), doB())
}
Experiment with this in the Go Playground: http://play.golang.org/p/orrJw2XMW8

Resources