GO 中的函数包装器 [英] Function Wrapper in GO

查看:39
本文介绍了GO 中的函数包装器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个函数包装器,它将接受一个函数并返回它的包装器版本.我试图实现的是在函数执行前后注入一些代码

I need a function wrapper, which will take a function and return the wrapper version of it. What I try to achieve is inject some code before and after of the function's execution

func funcWrapper(myFunc interface{}){
    fmt.Println("Before")
    //call myFunc
    fmt.Println("After")
}

推荐答案

如果知道函数的签名,就可以创建一个函数,该函数接受该函数类型的函数值,并返回另一个相同类型的函数值.您可以使用 函数文字 来执行您想要添加的额外功能,然后调用在适当的时候传递函数.

If you know the signature of the function, you can create a function that takes a function value of that function type, and returns another function value of the same type. You may use a function literal that does the extra functionality you want to add to it, and call the passed function when it's appropriate.

例如,假设我们有这个函数:

For example let's say we have this function:

func myfunc(i int) int {
    fmt.Println("myfunc called with", i)
    return i * 2
}

一个接受 int 并返回一个 int(其输入数字的两倍)的函数.

A function that takes an int and returns an int (double of its input number).

这是一个可能的包装器,它在调用之前和之后通过记录对其进行注释",还记录其输入和返回值:

Here's a possible wrapper that "annotates" it with logging before and after calling it, also logging its input and return value:

func wrap(f func(i int) int) func(i int) int {
    return func(i int) (ret int) {
        fmt.Println("Before, i =", i)
        ret = f(i)
        fmt.Println("After, ret =", ret)
        return
    }
}

示例测试:

wf := wrap(myfunc)
ret := wf(2)
fmt.Println("Returned:", ret)

输出(在 Go Playground 上试试):

Output (try it on the Go Playground):

Before, i = 2
myfunc called with 2
After, ret = 4
Returned: 4

由于 Go 不支持泛型,因此您必须为要支持的每种不同的函数类型执行此操作.或者您可以尝试使用 reflect.MakeFunc()a> 正如你在这个问题中看到的:Go 中任意函数的包装器,使用它会很痛苦.

Since Go does not support generics, you have to do this for each different function types you want to support. Or you may attempt to write a general solution using reflect.MakeFunc() as you can see in this question: Wrapper for arbitrary function in Go, it it's gonna be a pain to use it.

如果你想支持多种函数类型,最好是为每个不同的函数类型创建一个单独的包装器,这样每个函数类型都可以有正确的返回类型(具有正确参数和结果类型的函数类型).如果您还想支持没有参数和返回类型的包装函数,它可能看起来像这样:

If you want to support multiple function types, best would be to create a separate wrapper for each distinct function type, so each can have the proper return type (function type with proper parameter and result types). It could look like this if you'd also want to support wrapping functions with no parameter and return types:

func wrap(f func()) func() {
    return func() {
        fmt.Println("Before func()")
        f2()
        fmt.Println("After func()")
    }
}

func wrapInt2Int(f func(i int) int) func(i int) int {
    return func(i int) (ret int) {
        fmt.Println("Before func(i int) (ret int), i =", i)
        ret = f(i)
        fmt.Println("After func(i int) (ret int), ret =", ret)
        return
    }
}

您可以在如下所示的单个 wrap() 函数中完成它,但它的缺点(类型安全性较低,更难使用)超过了它的优点,所以我建议不要这样做我只想为不同的函数类型创建单独的包装函数.

You may do it in a single wrap() function like below, but its cons (less type safety, harder to use) out-weight its pros, so I'd advise against it and I would just create separate wrapper functions for separate function types.

让我们也支持包装一个没有参数和返回类型的函数:

Let's also support wrapping a function with no parameter and return types:

func myfunc2() {
    fmt.Println("myfunc2 called")
}

包装函数:

func wrap(f interface{}) interface{} {
    switch f2 := f.(type) {
    case func(i int) (ret int):
        return func(i int) (ret int) {
            fmt.Println("Before func(i int) (ret int), i =", i)
            ret = f2(i)
            fmt.Println("After func(i int) (ret int), ret =", ret)
            return
        }
    case func():
        return func() {
            fmt.Println("Before func()")
            f2()
            fmt.Println("After func()")
        }
    }
    return nil
}

测试:

wf := wrap(myfunc).(func(int) int)
ret := wf(2)
fmt.Println("Returned:", ret)

wf2 := wrap(myfunc2).(func())
wf2()

输出(在 Go Playground 上试试这个):

Output (try this one on the Go Playground):

Before func(i int) (ret int), i = 2
myfunc called with 2
After func(i int) (ret int), ret = 4
Returned: 4
Before func()
myfunc2 called
After func()

由于Go中没有泛型,所以这个方案只能有一个返回类型interface{},并且在使用的时候,它的返回值必须手动转换",type asserted 到您希望它返回的函数类型(例如 wf2 := wrap(myfunc2).(func())).

Since there is no generics in Go, this solution can only have a return type interface{}, and when using it, its return value have to be manually "converted", type asserted to the function type you expect it to return (e.g. wf2 := wrap(myfunc2).(func())).

这篇关于GO 中的函数包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆