How to define a function type which accepts any number of arguments in Go?
我尝试编写一个函数,它接受任何其他函数,并围绕它包装一个新函数。这就是我迄今为止所尝试的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 (); } |
当我编译这个时,我得到了错误:
1 | cannot use a (type func()) as type func(...interface { }) in function argument |
号
为什么没有参数的函数与参数数目可变的函数不兼容?我该怎么做才能使它们兼容?
更新:保护功能应与原始功能兼容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) } |
类型在Go中相当具体。你可以试试
1 2 3 | a := func(_ ...interface{}) { fmt.Println("unprotected") } |
或者,您可以使用
编辑:特别是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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") } |
号
输出为
1 2 3 4 | Protected unprotected Protected hello |
编辑:回答更新
就像我上面说的,类型在go中是相当具体的。protect函数返回一个类型
第一个更改保护也返回值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 } } |
。
然后生成一个转换函数:
1 2 3 4 5 6 | func convert(f func(...interface{}) (func(int) int) { return func(x int) int { r := f(x) return r[0].(int) } } |
那么你的电话看起来像
1 | take_func_int_int(convert(b)) |
。但我保证这不是你真正想做的。
退一步,尝试重新处理问题。在这些例子中,我完全消灭了类型安全。你想完成什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package main import"fmt" // Here's a function that will take an arbitrary number // of `int`s as arguments. func sum(nums ...int) { fmt.Print(nums,"") total := 0 for _, num := range nums { total += num } fmt.Println(total) } func main() { // Variadic functions can be called in the usual way // with individual arguments. sum(1, 2) sum(1, 2, 3) // If you already have multiple args in a slice, // apply them to a variadic function using // `func(slice...)` like this. nums := []int{1, 2, 3, 4} sum(nums...) } |
。