我需要一个函数包装器,它将获取一个函数并返回它的包装器版本。我试图实现的是在函数执行之前和之后注入一些代码
func funcWrapper(myFunc interface{}){
fmt.Println("Before")
//call myFunc
fmt.Println("After")
}
答案 0 :(得分:2)
如果您知道函数的签名,则可以创建一个函数,该函数接受该函数类型的函数值,并返回相同类型的另一个函数值。您可以使用function literal来执行您想要添加的额外功能,并在适当的时候调用传递的函数。
例如,让我们说我们有这个功能:
func myfunc(i int) int {
fmt.Println("myfunc called with", i)
return i * 2
}
一个函数,它接受int
并返回int
(输入数字的两倍)。
这是一个可能的包装,它可以注释"它在调用它之前和之后记录它,也记录它的输入和返回值:
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上尝试):
Before, i = 2
myfunc called with 2
After, ret = 4
Returned: 4
由于Go不支持泛型,因此必须为要支持的每种不同函数类型执行此操作。或者您可以尝试使用reflect.MakeFunc()
编写一般解决方案,正如您在此问题中所看到的那样:Wrapper for arbitrary function in Go,使用它会很痛苦。
如果要支持多种函数类型,最好是为每个不同的函数类型创建一个单独的包装器,这样每个函数类型都可以具有正确的返回类型(具有适当参数和结果类型的函数类型)。如果你还想支持没有参数和返回类型的包装函数,它可能看起来像这样:
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()
函数中执行此操作,但是它的缺点(类型安全性较低,使用难度较大)超出了它的优点,所以我建议反对它,我会为单独的函数类型创建单独的包装函数。
我们还支持包装没有参数和返回类型的函数:
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上试试这个):
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{}
,并且在使用时,其返回值必须手动"转换",{{3}到期望它返回的函数类型(例如wf2 := wrap(myfunc2).(func())
)。
答案 1 :(得分:0)
这是一种方法https://play.golang.org/p/ouzU2jiFDz2
package main
import (
"fmt"
)
func trace(funcName string) func() {
fmt.Println("pre", funcName)
return func() {
fmt.Println("post", funcName)
}
}
func doSomething(name string) {
defer trace("something")()
fmt.Println(name)
}
func main() {
doSomething("test")
}