首页 文章

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

提问于
浏览
6

我尝试编写一个函数,它接受任何其他函数并在其周围包装一个新函数 . 这是我到目前为止所尝试的:

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 ();
}

当我编译这个时,我得到错误:

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

为什么没有参数的函数与具有可变数量参数的函数不兼容?我该怎么做才能使它们兼容?

Update: 受保护的功能应与原始功能兼容:

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 回答

  • 0

    Go中的类型非常具体 . 你可以试试

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

    func (...interface{}) 并不意味着"any function that takes any number of any kind of arguments",这意味着"only a function which takes a variable number of interface{} arguments"

    或者,而不是 func(...interface{}) ,您可以使用 interface{}reflect 包 . 有关示例,请参见http://github.com/hoisie/web.go .

    编辑:具体来说,这个:

    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")
    }
    

    输出是

    Protected
    unprotected
    Protected
    hello
    

    编辑:回答更新

    就像我上面说的那样,Go中的类型非常具体 . 保护功能返回 func(...interface{}) 类型,永远不会分配给 func(int)int . 我认为你是一个非常气馁的代码片段,它会让它发挥作用 .

    首先改变保护也返回值:

    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
        }
    }
    

    然后做一个转换函数:

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

    然后你的电话会是这样的

    take_func_int_int(convert(b))
    

    但我保证这不是你真正想做的事情 .

    退一步,尝试重做问题 . 在这些例子中,我完全杀死了类型安全 . 你想达到什么目的?

  • 11
    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...)
    }
    

相关问题