Go语言中的函数 Package 器

bxfogqkk  于 2022-12-07  发布在  Go
关注(0)|答案(2)|浏览(138)

我需要一个函数 Package 器,它接受一个函数并返回它的 Package 器版本。

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

qni6mghb1#

如果知道函数的签名,则可以创建一个函数,该函数接受该函数类型的函数值,并返回相同类型的另一个函数值。可以使用函数文本来执行要添加到其中的额外功能,并在适当的时候调用传递的函数。
例如,假设我们有这个函数:

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

一个接受int并返回int(其输入数的两倍)的函数。
下面是一个可能的 Package 器,它在调用它之前和之后用日志记录来“注解”它,还记录它的输入和返回值:

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,用起来会很痛苦.
如果你想支持多个函数类型,最好是为每个不同的函数类型创建一个单独的 Package 器,这样每个函数类型都可以有合适的返回类型(带有合适参数和结果类型的函数类型)。如果你还想支持不带参数和返回类型的 Package 函数,可以像这样:

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()函数中这样做,如下所示,但它的缺点(类型安全性较低,更难使用)超过了它的优点,所以我建议不要这样做,我只会为不同的函数类型创建不同的 Package 函数。
让我们也支持 Package 一个没有参数和返回类型的函数:

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

Package 函数:

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{},并且在使用它的时候,它的返回值必须被手动“转换”,Assert为你期望它返回的函数类型(例如wf2 := wrap(myfunc2).(func()))。
参见相关:函数调用的Go类型

zzwlnbp8

zzwlnbp82#

这里有一种方法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")
}

相关问题