我该如何编写函数代理,该代理需要将接口{}强制转换为func(…x)…y,并将结果绑定到指针值?

I am trying to create a function, which acts as a proxy for executing a function.

It accepts a pointer to a value (which will be where the result is set), a func and a number of params. It executes the function and applies the result on the value.

My first challenge is executing the function as the declared type is not a func (and can't be). think I can achieve this using reflect.MakeFunc, but I am having no success.

An example of what I am trying to achieve below.

package main

import "fmt"

// Execute the function which returns this struct
type item struct {
    key        string
    value      string
    otherValue string
}

func todo(param string) (*item, error) {
    return &item{
        key: param,
    }, nil
}

type BindFunc struct {
    Params  func(params ...interface{}) *BindFunc
    Results func(results ...interface{}) *BindFunc
    Do      func()
}

// NewBindFunc is a proxy function should run the function and bind the results
// to the result
func NewBindFunc(fn interface{}) *BindFunc {
    b := &BindFunc{}

    b.Params = func(params ...interface{}) *BindFunc {
        return b
    }

    b.Results = func(results ...interface{}) *BindFunc {
        return b
    }

    b.Do = func() {
        // execute the function
    }

    return b
}

func main() {
    var result item
    var err error

    NewBindFunc(todo).
        Params("Param").
        Results(&result, &err).
        Do()

    fmt.Println(result.key)
}

Use Value.Call to call the function. Simplify the code by using methods on BindFunc instead of fields with functions.

type BindFunc struct {
    params  []interface{}
    results []interface{}
    fn      interface{}
}

func (bf *BindFunc) Params(params ...interface{}) *BindFunc {
    bf.params = params
    return bf
}

func (bf *BindFunc) Results(results ...interface{}) *BindFunc {
    bf.results = results
    return bf
}

func (bf *BindFunc) Do() {
    // Copy params to slice of reflect values.
    var params []reflect.Value
    for _, p := range bf.params {
        params = append(params, reflect.ValueOf(p))
    }

    // Invoke the function.
    results := reflect.ValueOf(bf.fn).Call(params)

    // Copy the results.
    for i, r := range results {
        reflect.ValueOf(bf.results[i]).Elem().Set(r)
    }
}

// NewBindFunc is a proxy function should run the function and bind the results
// to the result
func NewBindFunc(fn interface{}) *BindFunc {
    return &BindFunc{fn: fn}
}

Call it like this:

var result *item
var err error

NewBindFunc(todo).
    Params("Param").
    Results(&result, &err).
    Do()

Run it on the Playground.

The above code will panic if there's a mismatch in types, a mismatch in the number of arguments or a mismatch in the number of return values. The panic can be avoided by checking types using the reflect package, but I'll leave that as an exercise.

I don't know what the full scenario is, but it may be possible to replace all of this with a closure over the arguments and results:

var result *item
var err error
do := func() { result, err = todo("Param") }
do()