dtx63505 2011-05-18 15:48
浏览 253
已采纳

如何定义在Go中接受任意数量参数的函数类型?

I try to write a function which 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 the error:

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

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

Update: The protected function should 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)
}
  • 写回答

2条回答 默认 最新

  • dongzhang1839 2011-05-18 16:35
    关注

    Types are pretty concrete in Go. You could try

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

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

    Alternatively rather than func(...interface{}) you can just use interface{} and the reflect package. See http://github.com/hoisie/web.go for an example.

    EDIT: Specifically, 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 is

    Protected
    unprotected
    Protected
    hello
    

    EDIT: To answer the update

    Like I said above, types are pretty concrete in Go. The protect function returns a type func(...interface{}) which will never be assignable to func(int)int. I think you're probably either over-engineering your problem or misunderstanding it. However, here's a highly discouraged code snippet that would make it work.

    First change protect to also 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 make a convert function:

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

    Then your call would look like

    take_func_int_int(convert(b))
    

    But I promise this isn't what you actually want to do.

    Step back and try to rework the problem. I've completely killed type-safety in these examples. What are you trying to accomplish?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘