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 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?