Golang: указатель на функцию из строки (имя функции)
Есть ли шанс получить указатель на функцию из имени функции, представленной в виде строки? Это необходимо, например, для отправки какой-либо функции в качестве аргумента другой функции. Знаете, какое-то метапрограммирование.
Ответы
Ответ 1
Функции Go являются первоклассными значениями. Вам не нужно возвращаться к трюкам из динамических языков.
package main
import "fmt"
func someFunction1(a, b int) int {
return a + b
}
func someFunction2(a, b int) int {
return a - b
}
func someOtherFunction(a, b int, f func(int, int) int) int {
return f(a, b)
}
func main() {
fmt.Println(someOtherFunction(111, 12, someFunction1))
fmt.Println(someOtherFunction(111, 12, someFunction2))
}
площадка
Выход:
123
99
Если выбор функции зависит от некоторого известного значения времени выполнения, вы можете использовать карту:
m := map[string]func(int, int) int {
"someFunction1": someFunction1,
"someFunction2": someFunction2,
}
...
z := someOtherFunction(x, y, m[key])
Ответ 2
Принятый ответ - это, вероятно, то, что вам следует делать.
Вот подход, использующий рефлексию, который также позволяет передавать гибкое количество аргументов. В настоящее время требуется создание списка (карты) поддерживаемых функций вручную (см. метод main
), но это можно улучшить.
package main
import "fmt"
import "reflect"
import "errors"
func foo() {
fmt.Println("we are running foo")
}
func bar(a, b, c int) {
fmt.Println("we are running bar", a, b, c)
}
func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value, err error) {
f := reflect.ValueOf(m[name])
if len(params) != f.Type().NumIn() {
err = errors.New("The number of params is not adapted.")
return
}
in := make([]reflect.Value, len(params))
for k, param := range params {
in[k] = reflect.ValueOf(param)
}
result = f.Call(in)
return
}
func main() {
// nota bene: for perfect score: use reflection to build this map
funcs := map[string]interface{} {
"foo": foo,
"bar": bar,
}
Call(funcs, "foo")
Call(funcs, "bar", 1, 2, 3)
}
Вдохновение/источник
Ответ 3
Я не совсем понимаю, что вы хотите сделать. Принятый ответ должен охватывать основы всего, что вы пытаетесь сделать.
Я хотел бы добавить, что пакет crypto
имеет интересный способ косвенной регистрации других пакетов. В частности, посмотрите на crypto.go.
По сути, как это работает, пакет crypto
имеет пустую карту, подобную этой:
var regFuncs = make(map[key]func (arg) result)
Где "ключ" - это уникальный тип (типа int, string и т.д.), а значение - ожидаемый прототип функции.
Пакет затем зарегистрируется, используя функцию init:
func init() {
master.RegisterFunc("name", myFunc)
}
Сам пакет будет включен с использованием import _ "path/to/package"
.
И тогда у мастер-пакета будет какой-то способ извлечь эту функцию.
С crypto
вы можете использовать sha 256 следующим образом:
crypto.SHA256.New()
Но сначала вы должны включить его в свой основной файл следующим образом:
import _ "crypto/sha256"
Надеюсь, это поможет.
Ответ 4
Если функция является "Методом", вы можете использовать reflection.Value.MethodByName
см. отразить здесь документацию