Как создать новую функцию из другой функции, используя отражение - PullRequest
0 голосов
/ 03 апреля 2020

Использование этого кода в качестве шаблона

package main

import "fmt"

type myStruct struct {
    Value int
}

type counter int

func newFuncHandler(fn func(myStruct) error) (interface{}, *counter) {
    count := counter(0)

    newFn := func(e myStruct) error {
        count = count + 1
        return fn(e)
    }

    return newFn, &count
}

func main() {
    fn := func(d myStruct) error {
        // doing some stuff
        return nil
    }

    handle, c := newFuncHandler(fn)
    handleFn := handle.(func(d myStruct) error)

    handleFn(myStruct{Value: 2})
    handleFn(myStruct{Value: 2})
    handleFn(myStruct{Value: 2})
    handleFn(myStruct{Value: 2})
    handleFn(myStruct{Value: 2})

    fmt.Println(*c) // 5
}

как изменить newFuncHandler так, чтобы при наличии функции с неизвестной сигнатурой она возвращала функцию с такой же сигнатурой, но с дополнительным кодом для тела функции , newFuncHandler не должен знать типа myStruct

Например

func newFuncHandler(fn interface{}) (interface{}, *counter) {
    count := counter(0)
    // some reflection magic

    // newFn has the same signature as fn (hardcoded in this case)
    newFn := func(e myStruct) error {
        // add custom code 
        count = count + 1

        // call the original fn
        return fn(e)
    }

    return newFn, &count
}

1 Ответ

2 голосов
/ 03 апреля 2020

Используйте refle.MakeFun c, чтобы создать функцию. Используйте Value.Call для вызова функции.

func newFuncHandler(v interface{}) (interface{}, *counter) {
    count := counter(0)
    fn := reflect.ValueOf(v)
    newFn := reflect.MakeFunc(fn.Type(), func(args []reflect.Value) (results []reflect.Value) {
        count = count + 1
        return fn.Call(args)
    })
    return newFn.Interface(), &count
}

Запустите ее на игровой площадке .

...