使用反射更改界面下的指针类型和值 [英] Changing pointer type and value under interface with reflection
问题描述
我可以用反射来改变指针的值: v.Elem ().Set(reflect.ValueOf(& Greeter {Jack}).elem())
,它相当于 a =& Greeter {Jack}
。
但是我怎样才能做一个相当于 a =& Greeter2 {Jack}
?
UPDATE:不幸的是,在我试图解决的实际问题中,我无法解决原始变量( panic:reflect:reflect.Value.Set using unaddressable值
),这就是为什么我试图在指针级别解决。
func(g * Greeter2)String ()string {
returnHello2,My name is+ g.Name
}
并且在第一次初始化之后调用 a.String()
来查看它最初包含 * Greeter
价值,因为我们很快就会改变它。
var a fmt.Stringer
a =& Greeter {John }
fmt.Println(a.String())//你好,我的名字是John
v:= reflect.ValueOf(& a).Elem()
v.Set(reflect.ValueOf(& Greeter2 {Jack}))
fmt.Println(a.String())// Hello2,我的名字是Jack
a =& amp ; Greeter2 {Ron}
fmt.Println(a.String())// Hello2,我的名字是Ron
输出(在 Go Playground ):
您好,我的名字是John
Hello2,我的名字是Jack
Hello2,我的名字是Ron
没有改变接口的值和类型的东西,只能改变一个变量(有内存地址)中的数据,这个变量可能是接口类型的。
所以关键是:
$ b
- 从地址开始:
reflect.ValueOf( & a)
- 您必须设置一个指针值为
* Greeter2
implementsfmt.String
,但不是Greeter
。请参阅转到,X不会实现Y(...方法有一个指针接收器)。
有关更多详细信息和深入介绍,阅读:围棋博客:反思的法律
编辑:关于修改副本
我的答案的第一部分:无论何时您传递某个副本。这还包括将接口值传递给 reflect.ValueOf()
:它也会收到一份副本,所以你不能避免这种情况。唯一的方法是传递一个指针;因为指针也会被复制,但我们正在修改指向的值(而不是指针),它是相同的。
Is it possible to change pointer type and value of variable defined by interface?
I can change pointer value with reflection: v.Elem().Set(reflect.ValueOf(&Greeter{"Jack"}).Elem())
which is equivalent to a = &Greeter{"Jack"}
.
But how can I make a reflection equivalent for a = &Greeter2{"Jack"}
?
UPDATE: Unfortunately in real problem that I'm trying to solve I can not address original variable (panic: reflect: reflect.Value.Set using unaddressable value
), that's why I'm trying to workaround at pointer level.
Here is full example code:
package main
import (
"fmt"
"reflect"
)
type Greeter struct {
Name string
}
func (g *Greeter) String() string {
return "Hello, My name is " + g.Name
}
type Greeter2 struct {
Name string
}
func (g *Greeter2) String() string {
return "Hello, My name is " + g.Name
}
func main() {
var a fmt.Stringer
a = &Greeter{"John"}
v := reflect.ValueOf(a)
v.Elem().Set(reflect.ValueOf(&Greeter{"Jack"}).Elem())
//v.Elem().Set(reflect.ValueOf(&Greeter2{"Jack"}).Elem()) // panic: reflect.Set: value of type main.Greeter2 is not assignable to type main.Greeter
fmt.Println(a.String()) // Hello, My name is Jack
a = &Greeter2{"Ron"}
fmt.Println(a.String()) // Hello, My name is Ron
}
Everything in Go is passed by value. Interfaces too. When you pass a value of interface type, a copy of the interface value will be made (along with the (value;type)
inside it), and you will only be able to modify the copy which will not affect the original.
You have a variable a
of interface type. If you want to modify the value stored in this variable, you have to pass / use the address of this variable.
First let's modify the Greeter2.String()
method to know which one gets called:
func (g *Greeter2) String() string {
return "Hello2, My name is " + g.Name
}
And also call a.String()
after first init to see that it originally does contain a *Greeter
value as we'll soon change it.
var a fmt.Stringer
a = &Greeter{"John"}
fmt.Println(a.String()) // Hello, My name is John
v := reflect.ValueOf(&a).Elem()
v.Set(reflect.ValueOf(&Greeter2{"Jack"}))
fmt.Println(a.String()) // Hello2, My name is Jack
a = &Greeter2{"Ron"}
fmt.Println(a.String()) // Hello2, My name is Ron
Output (try it on the Go Playground):
Hello, My name is John
Hello2, My name is Jack
Hello2, My name is Ron
So essentially there is no such thing as changing the value and type of an interface value, only changing the data in a variable (that has a memory address) that may be of interface type.
So the key things were:
- Start from an address:
reflect.ValueOf(&a)
- And you have to set a pointer value into it as only
*Greeter2
implementsfmt.String
, but notGreeter
. See Go, X does not implement Y (... method has a pointer receiver) for details.
For more details and in-depth introducation, read: The Go Blog: The Laws of Reflection
Edit: about modifying a copy
First section of my answer: Whenever you pass something a copy is made. This also includes passing an interface value to reflect.ValueOf()
: that will also receive a copy, so you can't avoid this. Only way to make this work is to pass a pointer; because the pointer will also be copied, but we're modifying the pointed value (not the pointer) which is the same.
这篇关于使用反射更改界面下的指针类型和值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!