我可以使用反射在Go中创建一个新的函数吗?

huangapple go评论78阅读模式
英文:

Can I create a new function using reflection in Go?

问题

我有一个想法,可以在Go语言中使用接口来定义RPC风格的接口。所以对于一个给定的服务,我可以创建一个像这样的接口:

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

我想做的是使用反射来实现该接口,将方法调用转换为RPC调用,将输入参数进行编组,并将结果解组回方法的输出。我知道如果我能得到输入参数的[]interface{},我可以使用反射来进行服务调用。然而,我没有看到任何使用反射来动态创建实现接口的值的方法,即通过调用我的反射使用函数。有人知道如何做到这一点吗,即使使用unsafe也可以。

英文:

I have an idea to use interfaces in Go to define RPC style interfaces. So for a given service, I might create an interface like this:

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

What I would like to do is use reflection to implement that interface, translating method calls into RPC calls, Marshaling the input parameters, and Unmarshaling the results back into the output of the method. I know that if I can get a []interface{} of the input parameters I can use reflection to make the service call. However I don't see any way to use reflection to dynamically create a value that would implement the interface by calling my reflection-using functions. Does anyone know of a way to do this, even using unsafe?

答案1

得分: 13

你不能通过反射来创建一个带有附加方法的类型,以实例化该类型的对象。

你可能可以通过unsafe包中的大量技巧来实现这一点。但即使如此,这也将是一种巨大的痛苦。

如果你详细说明你试图解决的问题,社区可以提出替代的解决方法。

编辑(2015年7月23日):从Go 1.5开始,有reflect.FuncOfreflect.MakeFunc,它们正好可以实现你想要的功能。

英文:

You can not create a type with attached methods via reflection, as to instantiate an object of that type.

You could possibly achieve this with a lot of hackery through the unsafe package. But even then, it'd be a massive pain.

If you elaborated more on the problem you're trying to solve, the community could come up with alternatives ways of solving it.

Edit (23. July 2015): starting with Go 1.5 there's reflect.FuncOf and reflect.MakeFunc, which do exactly what you want.

答案2

得分: 7

看起来在Go 1.1中,reflect包将获得创建新的任意类型函数的能力: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)
英文:

It appears that the reflect package will gain the ability to create new arbitrarily typed functions in Go 1.1: reflect.MakeFunc.

(the following added in response to @nemo)

Instead of an interface, one could create a struct type:

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

得分: 0

我认为如果能够完全实现reflect.Type接口,可能可以实现您想要的功能,但是您无法实现它(未导出的方法)。然后,可能可以使用unsafe_New来实例化您的自定义类型。

总的来说,这不是一个好主意。

实现您想要的功能的下一个最好的方法可能是使用类似gob的东西。您可以使用gob作为中间语言,使用反射读取接口中的方法,将它们写入gob,并解码创建的gob代码以获取真正的Go对象。但我不确定这是否值得。

大多数情况下,通过在客户端上手动实现接口并转发方法调用,可以更安全地实现您的需求。

英文:

I think it might be possible to achieve what you want if one could fully implement the reflect.Type interface, which you can't (unexported methods). Then it could, maybe, be possible to instantiate your custom type by using unsafe_New.

All in all it is not a good idea to do so.

The next best thing to what you want is probably to use something like gob. You can use gob as intermediate language, read the methods from your interface using reflection, write them as gob and decode the created gob code to real Go objects. But I'm not sure if that's worth it.

Most of the time you're safer by manually implementing your interface on the client side
and forwarding the method calls.

答案4

得分: 0

由于Go语言的静态特性,目前无法动态实现接口。

我理解你想要实现的目标,还有其他场景也会受益于更高级的反射能力(例如用于单元测试的良好模拟框架)。


话虽如此,你可以通过一种方法绕过这个问题。你可以编写自己的工具,生成一个包含给定接口的RPC实现的Go源代码文件。

你需要使用AST库以及其他库来解析和处理源接口。

我曾经走过这条路(gostub工具;可以作为参考),我可以说这并不是一件有趣且容易的事情。不过,最终的结果还是可以接受的,因为Go提供了go:generate功能,这至少使得在接口发生变化后重新运行工具变得稍微容易一些。

英文:

Due to the static nature of the language, there is no way to implement an interface dynamically in Go at this point in time.

I understand what you want to achieve and there are other scenarios that would also benefit of a more advanced reflection capability (e.g. a good mocking framework for unit tests)


That said, there is a way that you could workaround this problem. You could write your own tool which generates a Go source code file containing a given RPC implementation of an interface.

You would have to use the AST library, as well as others, to parse and process the source interface.

Having gone down that path (gostub tool; can use as reference), I can say it is not at all fun and easy. Still, the end result is bearable since Go provides the go:generate functionality, which at least makes rerunning the tool, once an interface has changed, a tad easier.

huangapple
  • 本文由 发表于 2012年9月13日 07:45:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/12397557.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定