2012-09-12 2 views
10

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

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

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

+0

Оба нижеуказанных ответов точны и верны. Поскольку в этом есть Bounty, вы должны отметить один из них в качестве своего ответа. Вы не заставите никого говорить что-либо еще. –

ответ

8

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

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

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

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

+0

Вопрос в том, что интерфейс Go является потенциально отличным способом описания своего рода службы RPC. Однако, как вы уже подтвердили, сегодня (для большого интерфейса) существует целый ряд шаблонов кода, которые необходимо было бы создать для реализации интерфейса через вызовы RPC. Я понимаю, что код шаблона может быть автоматически создан с помощью какого-то внешнего инструмента, но было бы неплохо сделать все это с отражением. – Matt

+1

Не совсем. reflect.MakeFunc уже существует с момента перехода 1.1. reflect.FuncOf был добавлен в 1.5, но не позволяет создавать методы, которые необходимы для реализации произвольных интерфейсов. Нам понадобится возможность создавать новые «именованные» типы и определять методы для этих типов во время выполнения. – Matt

0

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

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

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

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

+0

Что такое 'unsafe_New'? – thwd

+1

'unsafe_New' - это функция, определенная в пакете' runtime' и используемая пакетом 'reflect' для создания новых объектов. Например, используется в функции ['Zero'] (http://golang.org/src/pkg/reflect/value.go#L1729) функции' reflect'. – nemo

5

Похоже, что пакет отражения получит возможность создавать новые произвольно типизированные функции в Go 1.1: reflect.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) 
+1

Это не даст вам ассоциации типов. Таким образом, не произвольная реализация интерфейсов. – nemo

+0

@nemo вы абсолютно правы, но см. Мое обновление выше. – Matt

+0

Ах да, это возможно сейчас, конечно. Неплохо. – nemo

0

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

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


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

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

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

Смежные вопросы