gpt4 book ai didi

pointers - 使用反射在接口(interface)下更改指针类型和值

转载 作者:IT王子 更新时间:2023-10-29 01:57:39 26 4
gpt4 key购买 nike

是否可以更改接口(interface)定义的变量的指针类型和值?

我可以通过反射更改指针值:v.Elem().Set(reflect.ValueOf(&Greeter{"Jack"}).Elem()) 等同于 a = &Greeter{"Jack"}.

但是我怎样才能为 a = &Greeter2{"Ja​​ck"} 做一个等效的反射?

更新:不幸的是,在我试图解决的实际问题中,我无法寻址原始变量(panic: reflect: reflect.Value.Set using unaddressable value),这就是我尝试的原因在指针级别解决方法。

Here是完整的示例代码:

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
}

最佳答案

Go 中的一切都是按值传递的。接口(interface)也是。当你传递接口(interface)类型的值时,接口(interface)值的副本将被创建(连同其中的 (value;type)),你将只能修改副本不影响原来的。

你有一个接口(interface)类型的变量a。如果你想修改存储在这个变量中的值,你必须传递/使用这个变量的地址。

首先让我们修改 Greeter2.String() 方法以了解调用了哪个方法:

func (g *Greeter2) String() string {
return "Hello2, My name is " + g.Name
}

并且还在第一次初始化后调用 a.String() 以查看它最初确实包含一个 *Greeter 值,因为我们很快就会更改它。

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

输出(在 Go Playground 上尝试):

Hello, My name is John
Hello2, My name is Jack
Hello2, My name is Ron

所以本质上不存在更改接口(interface)的值和类型这样的事情,只是更改可能是接口(interface)类型的变量(具有内存地址)中的数据。

所以关键是:

  1. 从一个地址开始:reflect.ValueOf(&a)
  2. 并且您必须为其设置一个指针值,因为只有 *Greeter2 实现了 fmt.String,而不是 Greeter。参见 Go, X does not implement Y (... method has a pointer receiver)了解详情。

更多细节和深入介绍,阅读:The Go Blog: The Laws of Reflection

编辑:关于修改副本

我的回答的第一部分:每当您传递某些内容时,都会制作一份副本。这还包括将接口(interface)值传递给 reflect.ValueOf():它也会收到一个副本,因此您无法避免这种情况。使这项工作的唯一方法是传递一个指针;因为指针也将被复制,但我们正在修改相同的pointed值(不是指针)。

关于pointers - 使用反射在接口(interface)下更改指针类型和值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46342228/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com