douzhen1234 2018-02-16 12:58
浏览 137

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")
}
  • 写回答

1条回答 默认 最新

  • doty58493 2018-02-16 13:28
    关注

    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
    }
    

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

    Example testing it:

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

    Output (try it on the Go Playground):

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

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

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

    The wrapper function:

    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
    }
    

    Testing it:

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

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

    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())).

    评论

报告相同问题?

悬赏问题

  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题