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

发布于 2024-11-08 06:15:56 字数 1037 浏览 0 评论 0原文

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

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

Why is a function without arguments not compatible to a function with a variable number of参量?我该怎么做才能使它们兼容?

更新: 受保护的函数应与原始函数兼容:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

〆一缕阳光ご 2024-11-15 06:15:59
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...)
}
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...)
}
困倦 2024-11-15 06:15:58

Go 中的类型非常具体。您可以尝试

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

func (...interface{}) 并不意味着“任何采用任意数量任何类型参数的函数”,它的意思是“仅采用可变数量的接口{的函数” 除了使用 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 中的类型非常具体。 protected 函数返回一个 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))

但我保证这不是您真正想要做的。

退后一步,尝试重新解决问题。在这些例子中我已经完全取消了类型安全。你想实现什么目标?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文