dstew32424 2019-04-03 00:31
浏览 36
已采纳

我该如何编写函数代理,该代理需要将接口{}强制转换为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)
}
  • 写回答

1条回答 默认 最新

  • dream3323 2019-04-03 01:29
    关注

    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()
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试