#go
#Вперед
Вопрос:
Я пытаюсь создать функцию, которая действует как прокси для выполнения функции.
Он принимает указатель на значение (в котором будет задан результат), функцию и ряд параметров. Он выполняет функцию и применяет результат к значению.
Моя первая задача — выполнить функцию, поскольку объявленный тип не является func
(и не может быть). думаю, я смогу достичь этого с помощью reflect.MakeFunc
, но у меня нет успеха.
Ниже приведен пример того, чего я пытаюсь достичь.
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 amp;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 := amp;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(amp;result, amp;err).
Do()
fmt.Println(result.key)
}
Ответ №1:
Используйте Ценность.Вызов для вызова функции. Упростите код, используя методы на BindFunc
вместо полей с функциями.
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 amp;BindFunc{fn: fn}
}
Назовите это так:
var result *item
var err error
NewBindFunc(todo).
Params("Param").
Results(amp;result, amp;err).
Do()
Запустите его на игровой площадке.
Приведенный выше код будет паниковать, если есть несоответствие в типах, несоответствие в количестве аргументов или несоответствие в количестве возвращаемых значений. Паники можно избежать, проверяя типы с помощью пакета reflect, но я оставлю это как упражнение.
Я не знаю, каков полный сценарий, но может быть возможно заменить все это закрытием аргументов и результатов:
var result *item
var err error
do := func() { result, err = todo("Param") }
do()
Комментарии:
1. Большое вам спасибо за ваш ответ. Я многому научился, читая ваш код.