2012-09-12 13 views
10

Tengo una idea para usar interfaces en Ir para definir interfaces de estilo RPC. Así que para un determinado servicio, podría crear una interfaz de esta manera:¿Puedo crear una nueva función utilizando la reflexión en Go?

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

Lo que me gustaría hacer es utilizar la reflexión para poner en práctica esa interfaz, método de traducción pone en llamadas RPC, cálculo de referencias de los parámetros de entrada y desempaquetar el resultados de nuevo en la salida del método. Sé que si puedo obtener una [] interfaz {} de los parámetros de entrada, puedo usar la reflexión para hacer la llamada de servicio. Sin embargo, no veo ninguna forma de usar la reflexión para crear dinámicamente un valor que implementaría la interfaz llamando a mis funciones de uso de reflexión. ¿Alguien sabe de una manera de hacer esto, incluso usando inseguro?

+0

Las dos respuestas a continuación son correctas y verdaderas. Como hay un Bounty en esto, debes marcar uno de ellos como tu respuesta. No conseguirás que nadie diga nada más. –

Respuesta

8

No se puede crear un tipo con métodos adjuntos a través de la reflexión, como para crear una instancia de un objeto de ese tipo.

Usted podría lograr esto con una gran cantidad de hackers a través del paquete unsafe. Pero incluso entonces, sería un dolor masivo.

Si profundizó más en el problema que está tratando de resolver, la comunidad podría encontrar formas alternativas de resolverlo.

Editar (23. Julio 2015): comenzando con Go 1.5 hay reflect.FuncOf y reflect.MakeFunc, que hacen exactamente lo que usted desea.

+0

El punto de la pregunta es que una interfaz Go es potencialmente una gran manera de describir algún tipo de servicio RPC. Sin embargo, como ha confirmado, hoy (para una interfaz de gran tamaño) hay una gran cantidad de código repetitivo que debería crearse para implementar la interfaz a través de llamadas RPC. Me doy cuenta de que el código repetitivo podría crearse automáticamente con alguna herramienta externa, pero sería genial poder hacerlo todo con reflexión. – Matt

+1

No del todo. reflect.MakeFunc ya existe desde Go 1.1. reflect.FuncOf se agregó en 1.5, pero no permite la creación de métodos, que son necesarios para implementar interfaces arbitrarias. Lo que necesitaríamos sería la capacidad de crear nuevos tipos "nombrados" y definir métodos en esos tipos en tiempo de ejecución. – Matt

0

Creo que es posible lograr lo que desea si se puede implementar completamente la interfaz reflect.Type, que no se puede (métodos no exportados). Entonces, tal vez, sea posible crear una instancia de su tipo personalizado utilizando unsafe_New.

En general, no es una buena idea hacerlo.

Lo siguiente que probablemente desee es usar algo como gob. Puede usar gob como lenguaje intermedio, leer los métodos de su interfaz utilizando reflexión, escribirlos como gob y decodificar el código gob creado para objetos Go reales. Pero no estoy seguro si eso lo vale.

La mayoría de las veces está más seguro implementando manualmente su interfaz en el lado del cliente y reenviando las llamadas al método.

+0

¿Qué es 'inseguro_Nuevo'? – thwd

+1

'unsafe_New' es la función definida en el paquete' runtime' y utilizada por el paquete 'reflect' para crear objetos nuevos. Por ejemplo, se usa en la función ['Zero'] (http://golang.org/src/pkg/reflect/value.go#L1729) de' reflect'. – nemo

5

Parece que el paquete reflect obtendrá la capacidad de crear nuevas funciones escritas arbitrariamente en Go 1.1: reflect.MakeFunc.

(añade lo siguiente en respuesta a @nemo)

En lugar de una interfaz, se podría crear un tipo de estructura:

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

Sin embargo, esto no le dará una asociación de tipo. Entonces no hay implementación arbitraria de interfaces. – nemo

+0

@nemo tienes toda la razón, pero mira mi actualización más arriba. – Matt

+0

Ah sí, eso es posible ahora, por supuesto. No está mal. – nemo

0

Debido a la naturaleza estática de la lengua, no hay manera implementar una interfaz dinámicamente en Ir en este punto en el tiempo.

entiendo lo que quiere lograr y hay otros escenarios que también se beneficiarían de una capacidad de reflexión más avanzada (por ejemplo, un buen marco de burla para las pruebas unitarias)


Dicho esto, hay un camino que podría solucionar este problema Puede escribir su propia herramienta que genere un archivo de código fuente Go que contenga una implementación RPC dada de una interfaz.

Debería utilizar la biblioteca AST, así como otras, para analizar y procesar la interfaz de origen.

Después de haber recorrido ese camino (herramienta gostub, puede utilizar como referencia), puedo decir que no es para nada divertido y fácil. Aún así, el resultado final es soportable ya que Go proporciona la funcionalidad go:generate, que al menos hace que volver a ejecutar la herramienta, una vez que la interfaz ha cambiado, sea un poco más fácil.

Cuestiones relacionadas