【问题标题】:Can I create a new function using reflection in Go?我可以在 Go 中使用反射创建一个新函数吗?
【发布时间】:2023-03-11 01:17:02
【问题描述】:

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

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

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

【问题讨论】:

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

标签: reflection go


【解决方案1】:

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

你可以通过unsafe 包通过大量的hacky 来实现这一点。但即便如此,这也是一种巨大的痛苦。

如果您详细说明您要解决的问题,社区可能会提出解决问题的替代方法。

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

【讨论】:

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

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

【讨论】:

  • 这不会给你一个类型关联。所以没有任意实现接口。
【解决方案3】:

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

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

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

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

【讨论】:

  • unsafe_New 是在runtime 包中定义的函数,由reflect 包用于创建新对象。例如用在reflectZero函数中。
【解决方案4】:

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

我了解您想要实现的目标,并且还有其他场景也可以受益于更高级的反射功能(例如,用于单元测试的良好模拟框架)


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

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

沿着这条路走下去(gostub 工具;可以作为参考),我可以说它一点也不有趣和容易。尽管如此,最终结果还是可以忍受的,因为 Go 提供了 go:generate 功能,这至少使得在界面更改后重新运行该工具会更容易一些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-25
    • 2011-04-05
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多