Go中任意函数的 Package 器

i7uq4tfw  于 12个月前  发布在  Go
关注(0)|答案(5)|浏览(95)

有没有可能为Go中的任意函数创建一个 Package 器,它将接受相同的参数并返回相同的值?
我不是在谈论看起来完全一样的 Package 器,它可能看起来不同,但它应该解决问题。
例如,问题可能是创建任意函数的 Package 器,该 Package 器首先在缓存中查找函数调用的结果,并且仅在缓存未命中的情况下执行 Package 的函数。

snvhrwxg

snvhrwxg1#

答案基于@joshlf13的想法和答案,但对我来说似乎更简单。

package main

import (
    "fmt"
    "reflect"
)

type (
    // Type of function being wrapped
    sumFuncT func(int, int) (int)

    // Type of the wrapper function
    wrappedSumFuncT func(sumFuncT, int, int) (int)
)

// Wrapper of any function
// First element of array is the function being wrapped
// Other elements are arguments to the function
func genericWrapper(in []reflect.Value) []reflect.Value {
    // this is the place to do something useful in the wrapper
    return in[0].Call(in[1:])
}

// Creates wrapper function and sets it to the passed pointer to function
func createWrapperFunction(function interface {}) {
    fn := reflect.ValueOf(function).Elem()
    v := reflect.MakeFunc(reflect.TypeOf(function).Elem(), genericWrapper)
    fn.Set(v)
}

func main() {
    var wrappedSumFunc wrappedSumFuncT

    createWrapperFunction(&wrappedSumFunc)

    // The function being wrapped itself
    sumFunc := func (a int, b int) int {
        return a + b
    }

    result := wrappedSumFunc(sumFunc, 1, 3)
    fmt.Printf("Result is %v", result)
}

字符串

oymdgrw7

oymdgrw72#

基于以前的答案,并使用Go的新通用功能,我相信这可以非常优雅地实现(playground link):

package main

import (
    "fmt"
    "reflect"
)

// Creates wrapper function and sets it to the passed pointer to function
func wrapFunction[T any](function T) T {
    v := reflect.MakeFunc(reflect.TypeOf(function), func(in []reflect.Value) []reflect.Value {
        // This is the place to intercept your call.
        fmt.Println("Params are:", in)

        f := reflect.ValueOf(function)
        return f.Call(in)
    })
    return v.Interface().(T)
}

func main() {
    // The function being wrapped itself
    sum := func(a int, b int) int {
        return a + b
    }
    wrapped := wrapFunction(sum)

    fmt.Printf("Result is %v", wrapped(1, 3))
}

字符串

798qvoo8

798qvoo83#

这里有一个使用reflect.MakeFun的解决方案。这个特定的解决方案假设您的转换函数知道如何处理每种不同类型的函数。请在操作中观看:http://play.golang.org/p/7ZM4Hlcqjr

package main

import (
    "fmt"
    "reflect"
)

type genericFunction func(args []reflect.Value) (results []reflect.Value)

// A transformation takes a function f,
// and returns a genericFunction which should do whatever
// (ie, cache, call f directly, etc)
type transformation func(f interface{}) genericFunction

// Given a transformation, makeTransformation returns
// a function which you can apply directly to your target
// function, and it will return the transformed function
// (although in interface form, so you'll have to make
// a type assertion).
func makeTransformation(t transformation) func(interface{}) interface{} {
    return func(f interface{}) interface{} {
        // g is the genericFunction that transformation
        // produced. It will work fine, except that it
        // takes reflect.Value arguments and returns
        // reflect.Value return values, which is cumbersome.
        // Thus, we do some reflection magic to turn it
        // into a fully-fledged function with the proper
        // type signature.
        g := t(f)

        // typ is the type of f, and so it will also
        // be the type that of the function that we
        // create from the transformation (that is,
        // it's essentially also the type of g, except
        // that g technically takes reflect.Value
        // arguments, so we need to do the magic described
        // in the comment above).
        typ := reflect.TypeOf(f)

        // v now represents the actual function we want,
        // except that it's stored in a reflect.Value,
        // so we need to get it out as an interface value.
        v := reflect.MakeFunc(typ, g)
        return v.Interface()
    }
}

func main() {
    mult := func(i int) int { return i * 2 }

    timesTwo := func(f interface{}) genericFunction {
        return func(args []reflect.Value) (results []reflect.Value) {
            // We know we'll be getting an int as the only argument,
            // so this type assertion will always succeed.
            arg := args[0].Interface().(int)

            ff := f.(func(int) int)

            result := ff(arg * 2)
            return []reflect.Value{reflect.ValueOf(result)}
        }
    }

    trans := makeTransformation(timesTwo)

    // Since mult multiplies its argument by 2,
    // and timesTwo transforms functions to multiply
    // their arguments by 2, f will multiply its
    // arguments by 4.
    f := trans(mult).(func(int) int)

    fmt.Println(f(1))
}

字符串

2j4z5cfb

2j4z5cfb4#

我想到的最好的方法是接受一个函数def并返回一个接口,之后需要类型Assert:

func Wrapper(metaParams string, f func() (interface{}, string, error)) (interface{}, error) {
    // your wrapper code
    res, metaResults, err := f()
    // your wrapper code
    return res, err
}

字符串
然后使用这个也需要一点工作来像 Package 器一样工作:

resInterface, err := Wrapper("data for wrapper", func() (interface{}, string, error) {
    res, err := YourActualFuntion(whatever, params, needed)
    metaResults := "more data for wrapper"
    return res, metaResults, err
}) // note f() is not called here! Pass the func, not its results
if err != nil {
    // handle it
}
res, ok := resInterface.(actualType)
if !ok {
    // handle it
}


好处是它有点通用,可以处理任何带有1个返回类型+错误的东西,并且不需要反射。
缺点是这需要大量的工作,因为它不是一个简单的 Package 器或装饰器。

bqf10yzr

bqf10yzr5#

像这样吗?

var cache = make(map[string]string)

func doStuff(key string) {
   //do-something-that-takes-a-long-time
   cache[key] = value

   return value
}

fun DoStuff(key string) {
   if v, ok := cache[key]; ok {
        return v
   }

   return doStuff(key)
}

字符串

相关问题