pointers - Golang 反射 : Can't set fields of interface wrapping a struct

标签 pointers reflection interface struct go

我正在尝试实现一种方法,该方法可以更改可以具有任意结构的对象中的字段值。当我有指向结构的指针时,字段的遍历没有问题。但是,当我有一个不包含指向结构的指针而是结构本身的接口(interface)时,我无法更改字段,简而言之:

// The following doesn't work
var x interface{} = A{Str: "Hello"}
// This panics: reflect: call of reflect.Value.Field on ptr Value
reflect.ValueOf(&x).Field(0).SetString("Bye")
// This panics: reflect: call of reflect.Value.Field on interface Value
reflect.ValueOf(&x).Elem().Field(0).SetString("Bye")
// This panics: reflect: reflect.Value.SetString using unaddressable value
reflect.ValueOf(&x).Elem().Elem().Field(0).SetString("Bye")
// This prints `false`. But I want this to be settable
fmt.Println(reflect.ValueOf(&x).Elem().Elem().Field(0).CanSet())

// This works
var z interface{} = &A{Str: "Hello"}
// This prints `true`
fmt.Println(reflect.ValueOf(z).Elem().Field(0).CanSet())

长篇:http://play.golang.org/p/OsnCPvOx8F

我已阅读 The Laws of Reflection所以我知道只有当我有一个指向结构的指针时我才能修改字段。所以我现在的问题是:如何获得指向结构数据的指针?

更新:

我基本上使用 y := reflect.New(reflect.TypeOf(x)) 让它工作,所以现在 y 的值是可设置的。有关详细示例,请参见:https://gist.github.com/hvoecking/10772475

最佳答案

您似乎试图修改存储在接口(interface)变量中的动态值。您可以对接口(interface)变量执行的唯一操作是获取或设置动态值(制作副本的操作),以及检查存储值的类型。

要理解为什么会这样,假设有这样一个操作,我们有以下代码:

var ptr *A = pointer_to_dynamic_value(x)
x = B{...}

ptr 现在代表什么?在为接口(interface)变量分配新值时,该语言可以自由地重用存储,因此 ptr 现在可能指向 B 值的内存,这破坏了类型安全语言(使用当前编译器的存储仅保证可用于小值,但重点仍然存在)。

改变存储在接口(interface)中的值的唯一安全方法是将值复制出来,然后分配回修改后的版本。例如:

a := x.(A)
a.Str = "Bye"
x = a

reflect 包反射(reflect)了这些限制,因此表示动态值字段的 reflect.Value 被认为是只读的。

您可以在第一个示例中设置字段,因为 z 的动态值是 *A 指针而不是结构本身:这意味着引用的结构可以修改。

关于pointers - Golang 反射 : Can't set fields of interface wrapping a struct,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23043510/

相关文章:

java - java/scala 中的原始对象大小和 'as<SomePrimitive>Buffer() 方法调用

c# - 如何从接口(interface)返回派生程度更高的类型?

c++ - 发布由指针管理的列表的添加和打印元素

c - 如何在 C 中为我的数据结构分配内存

C - "char var[]"和 "char *var"之间的区别?

go - 如何使用反射将结构值转换为结构指针

c# - 使用反射更新列表中的值

c++ - 后增量运算符重载中的指针

c# - 如何序列化 IList<T> 等接口(interface)

go - 在非本地包中扩展接口(interface)方法