How to determine the type of function that takes any number of arguments in Go?

I am trying to write a function that takes any other function and wraps a new function around it. This is what I have tried so far:

  package main

 import (
     "fmt"
 )

 func protect (unprotected func (... interface {})) (func (... interface {})) {
     return func (args ... interface {}) {
         fmt.Println ("protected");
         unprotected (args ...);
     };
 }

 func main () {
     a: = func () {
         fmt.Println ("unprotected");
     };
     b: = protect (a);
     b ();
 }

When I compile this, I get an error:

cannot use a (type func()) as type func(...interface { }) in function argument 

Why is a function with no arguments incompatible with a function with a variable number of arguments? What can I do to make them compatible?

Update: A protected function must be compatible with the original:

  func take_func_int_int (f func (x int) (y int)) (int) {
     return f (1)
 }

 func main () {

     a: = func (x int) (y int) {
         return 2 * x
     }
     b: = protect (a)

     take_func_int_int (a)
     take_func_int_int (b)
 }
+4
source share
1 answer

Types are pretty specific in Go. You can try

 a := func(_ ...interface{}) { fmt.Println("unprotected") } 

func (...interface{}) does not mean "any function that takes any number of any arguments", it means "only a function that takes a variable number of interface arguments {}"

Alternatively, instead of func(...interface{}) you can simply use the interface{} and reflect package. For an example, see http://github.com/hoisie/web.go .

EDIT: In particular, this:

 package main import ( "fmt" "reflect" ) func protect(oldfunc interface{}) (func (...interface{})) { if reflect.TypeOf(oldfunc).Kind() != reflect.Func { panic("protected item is not a function") } return func (args ...interface{}) { fmt.Println("Protected") vargs := make([]reflect.Value, len(args)) for n, v := range args { vargs[n] = reflect.ValueOf(v) } reflect.ValueOf(oldfunc).Call(vargs) } } func main() { a := func() { fmt.Println("unprotected") } b := func(s string) { fmt.Println(s) } c := protect(a) d := protect(b) c() d("hello") } 

Ouput -

 Protected unprotected Protected hello 

EDIT: to respond to the update

As I said, types are pretty specific in Go. The security function returns a type of func(...interface{}) that will never be assigned to func(int)int . I think that you are probably underestimating your problem too much or underestimating it. However, there is a very discouraged piece of code that will make it work.

The first change also protects the return values:

 func protect(oldfunc interface{}) (func (...interface{}) []interface{}) { if reflect.TypeOf(oldfunc).Kind() != reflect.Func { panic("protected item is not a function") } return func (args ...interface{}) []interface{} { fmt.Println("Protected") vargs := make([]reflect.Value, len(args)) for n, v := range args { vargs[n] = reflect.ValueOf(v) } ret_vals := reflect.ValueOf(oldfunc).Call(vargs) to_return := make([]interface{}, len(ret_vals)) for n, v := range ret_vals { to_return[n] = v.Interface() } return to_return } } 

Then execute the conversion function:

 func convert(f func(...interface{}) (func(int) int) { return func(x int) int { r := f(x) return r[0].(int) } } 

Then your call will look like

 take_func_int_int(convert(b)) 

But I promise that this is not what you really want to do.

Go back and try to redo the problem. In these examples, I completely killed type safety. What are you trying to accomplish?

+11
source

All Articles