如何使用反射在运行时更改方法实现?

10

我有这个类型的实现:

type A struct{
  name string
}

func (a A) getName() string {
  return "My name is " + a.name 
}

我如何使用反射更改此类型的方法getName()的实现?例如,我想要使用下面的实现而不是当前的实现:

func newGetName() string {
  return "test reflection"
} 

1
你不能这样做。这种疯狂的事情会让你改变任何(已导出的)方法为任意的、甚至是有害的东西。你必须寻找其他解决问题的方法。 - Volker
2个回答

11

Go是一种编译语言,因此不可能在运行时修改事物的实现。您可以更改函数指针指向的位置:

var getName func(string) = func(name string) {
    return "my name is " + name
}

为了让它在一个结构中生效,你需要采用一些技巧。首先将getName添加为A的成员:
type A struct {
    name string
    getName func() string
}

然后我们将指向该结构体的指针作为隐式参数(即闭包)封装:

foo := &A{name: "Hans"}
foo.getName = func() string {
    return "my name is " + name
}

现在你可以调用 A.getName() 函数,结果为 "我的名字是汉斯"。你可以正常使用方法表达式和其他许多特性,但是 getName 是一个 结构体成员 而不是 A方法,所以请记住这一点。如果你想给 getName 赋予新的含义,请将其分配为不同的值:
foo.getName = func() string {
    return "test reflection"
}

如果您预先知道getName可能会有哪些实现,另一个特别适用的想法是向A添加一个新成员,指出getName目前拥有哪种实现,然后切换到该变量。


这似乎比我的答案更接近OP想要的。+1 - VonC

7
注意到 Go 的惯用方式是 不要 这样做,而是使用接口:

请查看这个例子

包 main

import "fmt"

type Aer interface {
    getName() string
}

type A struct {
    name string
}

func (a A) getName() string {
    return "My name is " + a.name
}

type testA struct {
    a A
}

func (ta testA) getName() string {
    return "NEW: My name is " + ta.a.name
}
func main() {
    a := A{name: "nameA"}
    fmt.Println(a.getName())
    ta := testA{a: a}
    fmt.Println(ta.getName())
}

输出:

My name is nameA
NEW: My name is nameA

没错!你不能改变它。我也没有。这就是为什么我用一个接口来包装你的对象。 - VonC
你需要使用“ta”而不是“a”来调用新方法。我无法进行这种替换。 - Interloper
@Interloper,你的方法没有被导出,这意味着我怀疑你无法通过反射调用它。 - VonC
我可以改变指向方法实现的指针吗? - Interloper
看起来使用 unsafereflct.MakeFunc() 存在一些技巧可能会奏效,但除了挑战之外,这真的不是任何人在现实生活中都应该做的事情。 - Not_a_Golfer
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接