Могу ли я создать новую функцию, используя отражение в Go?

У меня есть идея использовать интерфейсы в Go для определения интерфейсов стиля RPC. Поэтому для данной службы я мог бы создать такой интерфейс:

type MyService interface{
  Login(username, password string) (sessionId int, err error)
  HelloWorld(sessionId int) (hi string, err error)
}

То, что я хотел бы сделать, это использовать отражение для реализации этого интерфейса, перевода вызовов метода в вызовы RPC, Marshaling входных параметров и Unmarshaling результатов обратно в вывод метода. Я знаю, что если я смогу получить [] интерфейс {} входных параметров, я могу использовать отражение для вызова службы. Однако я не вижу никакого способа использовать отражение для динамического создания значения, которое реализует интерфейс, вызывая мои функции, использующие отражение. Кто-нибудь знает способ сделать это, даже используя небезопасные?

Ответ 1

Вы не можете создать тип с прикрепленными методами через отражение, чтобы создать экземпляр объекта такого типа.

Вы могли бы достичь этого с помощью большого количества хакеров через пакет unsafe. Но даже тогда это было бы огромной болью.

Если вы более подробно остановитесь на проблеме, которую пытаетесь решить, сообщество может найти альтернативные способы ее решения.

Изменить (23. июля 2015 года): начиная с Go 1.5 там reflect.FuncOf и reflect.MakeFunc, которые делают именно то, что вы хотите.

Ответ 2

Похоже, что пакет отражения получит возможность создавать новые произвольно типизированные функции в Go 1.1: отражать .MakeFunc.

(добавлено в ответ на @nemo)

Вместо интерфейса можно создать тип структуры:

type MyService struct{
  Login func(username, password string) (sessionId int, err error)
  HelloWorld func(sessionId int) (hi string, err error)
}

autorpc.ImplementService(&MyService, MyServiceURL)
session, err := MyService.Login(username, password)
stringout, err := MyService.HelloWorld(session)

Ответ 3

Я думаю, что можно добиться того, чего вы хотите, если бы вы могли полностью реализовать интерфейс reflect.Type, который вы не можете (неэкспортированные методы). Тогда, возможно, возможно создать экземпляр своего пользовательского типа с помощью unsafe_New.

В целом это не очень хорошая идея.

Следующее лучшее, что вам нужно, - это, вероятно, использовать что-то вроде gob. Вы можете использовать gob как промежуточный язык, читать методы из вашего интерфейса с помощью отражения, записывать их как gob и декодировать созданный код gob для реальных объектов Go. Но я не уверен, что это того стоит.

В большинстве случаев вы более безопасны, вручную применяя свой интерфейс на стороне клиента и пересылка вызовов метода.

Ответ 4

Из-за статической природы языка невозможно реализовать интерфейс динамически в Go в этот момент времени.

Я понимаю, чего вы хотите достичь, и есть другие сценарии, которые также принесут пользу более продвинутой способности отражения (например, хорошая фальшивая основа для модульных тестов)


Тем не менее, есть способ, которым вы могли бы решить эту проблему. Вы можете написать собственный инструмент, который генерирует файл исходного кода Go, содержащий заданную реализацию интерфейса RPC.

Вам нужно будет использовать библиотеку AST, а также другие, для анализа и обработки исходного интерфейса.

Спустившись по этому пути (gostub, можно использовать в качестве ссылки), могу сказать, что это совсем не весело и просто, Тем не менее, конечный результат является терпимым, поскольку Go предоставляет функциональность go:generate, которая, по крайней мере, делает повторный запуск инструмента после изменения интерфейса немного проще.