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

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

How to change method implementation in run-time using reflection?

问题

我有这个类型的实现:

type A struct{
  name string
}

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

我如何使用反射更改该类型的getName()方法的实现?
例如,我想使用以下实现代替当前实现:

func newGetName() string {
  return "test reflection"
}
英文:

I have this type implementation:

type A struct{
  name string
}

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

How I can change implementation of method getName() for this type using reflection?
For example, I want use next implementation instead of current:

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

答案1

得分: 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 " + foo.name
}

现在你可以调用A.getName(),结果是"my name is hans"。你可以正常使用方法表达式和许多其他特性,但是getName是一个结构体成员,而不是A方法,所以请记住这一点。当你想要给getName赋予新的含义时,将其赋值为其他内容:

foo.getName = func() string {
    return "test reflection"
}

另一个特别适用的想法是,如果你事先知道getName可能有哪些实现,可以向A添加一个新的成员,表示getName当前的实现,然后根据这个变量进行切换。

英文:

Go is a compiled language. As such, it's not possible to modify the implementation of things at runtime. What you can do is changing the place function pointers point to:

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

In order to make this work with a structure, you have to resort to a few tricks. First add getName as a member to A:

type A struct {
    name string
    getName func() string
}

Then we enclose a pointer to the structure as an implicit (i.e. closed over) parameter:

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

Now you can call A.getName() and the result is "my name is hans". You can use method expressions and many other features just fine, but getName is a structure member and not a method of A, so keep this in mind. When you want to give a new meaning to getName, assign something different to it:

foo.getName = func() string {
    return "test reflection"
}

Another idea that is especially applicable if you know in advance what implementations getName could have is to add a new member to A that says what implementation getName currently has and then switch over this variable.

答案2

得分: 7

请注意,Go语言的惯用方式是这样做,而是使用接口代替:

参考这个例子

package 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
英文:

Note the idiomatic Go is to not do that and use interface instead:

See this example:

package 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())
}

Output:

My name is nameA
NEW: My name is nameA

huangapple
  • 本文由 发表于 2015年2月18日 14:39:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/28577489.html
匿名

发表评论

匿名网友

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

确定