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


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

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

我想要做的是使用反射来实现该接口,将方法调用转换为RPC调用,对输入参数进行封送,并将结果解组回到方法的输出中。我知道如果我能得到输入参数的[]接口{},我可以使用反射来进行服务调用。但是,我没有看到任何方法使用反射来动态创建一个值,通过调用我的反射使用函数来实现接口。有没有人知道这样做的方法,即使使用不安全?


2690
2017-09-12 23:45


起源

以下两个答案都是准确而真实的。由于此处有赏金,您应该将其中一个标记为您的答案。你不会让任何人说别的。 - Jeremy Wall


答案:


您无法通过反射创建具有附加方法的类型,以实例化该类型的对象。

你可以通过很多hackery实现这一目标 unsafe 包。但即便如此,这也是一次巨大的痛苦。

如果你详细阐述了你试图解决的问题,那么社区可以提出解决问题的替代方法。

编辑(2015年7月23日):从Go 1.5开始 reflect.FuncOf 和 reflect.MakeFunc,这正是你想要的。


9
2017-09-13 11:53



问题的关键在于Go接口可能是描述某种RPC服务的好方法。但是,正如您已经确认的那样,今天(对于大型接口),必须创建大量样板代码才能通过RPC调用实现接口。我意识到可以使用一些外部工具自动创建样板代码,但是能够通过反射完成所有操作将非常酷。 - Matt
不完全的。 reflect.MakeFunc自Go 1.1以来就已存在。 reflect.FuncOf在1.5中添加,但不支持创建实现任意接口所需的方法。我们需要的是能够在运行时创建新的“命名”类型并在这些类型上定义方法。 - Matt


似乎反射包将获得在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)

5
2017-12-05 16:19



这不会给你一个类型关联。所以没有任意的接口实现。 - nemo
@nemo你是绝对正确的,但请看我上面的更新。 - Matt
啊,是的,当然可以。不错。 - nemo


我认为,如果一个人可以完全实现,你可能会实现你想要的 reflect.Type 接口,你不能(未导出的方法)。然后,也许可以通过使用实例化您的自定义类型 unsafe_New

总而言之,这样做并不是一个好主意。

你想要的下一个最好的事情可能是使用类似的东西 凝块。您可以使用gob作为中间语言,使用反射从界面读取方法,将它们写为gob并将创建的gob代码解码为真正的Go对象。但我不确定这是否值得。

大多数情况下,通过在客户端手动实现界面,您会更安全 并转发方法调用。


0
2017-09-13 12:15



什么是 unsafe_New? - thwd
unsafe_New 是在中定义的函数 runtime 包装和使用 reflect 用于创建新对象的包。例如用于 Zero 的功能 reflect。 - nemo


由于语言的静态特性,此时无法在Go中动态实现接口。

我理解您想要实现的目标,还有其他方案也可以从更高级的反射功能中受益(例如,单元测试的良好模拟框架)


也就是说,有一种方法可以解决这个问题。您可以编写自己的工具,生成包含接口的给定RPC实现的Go源代码文件。

你必须使用 AST 库以及其他人来解析和处理源接口。

走下那条路(gostub 工具;可以用作参考),我可以说它一点也不好玩。尽管如此,最终的结果是可以忍受的,因为Go提供了 go:generate功能,至少可以重新运行工具,一旦界面发生变化,就会更容易。


0
2017-07-22 18:55