简体   繁体   English

Golang反射:无法设置包装结构的接口字段

[英]Golang reflection: Can't set fields of interface wrapping a struct

I am trying to implement a method that changes the value of fields in an object that can have an arbitrary structure. 我正在尝试实现一个方法,该方法可以更改可以具有任意结构的对象中的字段值。 The traversion of the fields is no problem when I have the pointer to a struct. 当我有一个指向结构的指针时,字段的转换没有问题。 But I can not manage to change the fields when I have an interface that does not wrap a pointer to a struct but the struct itself, in short: 但是,当我的接口没有包装指向结构的指针但结构本身时,我无法改变字段,简而言之:

// 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())

In long: http://play.golang.org/p/OsnCPvOx8F 长: http//play.golang.org/p/OsnCPvOx8F

I have read The Laws of Reflection so I am aware that I may only modify fields when I have a pointer to a struct. 我已经阅读了反射法则,所以我知道当我有一个指向结构的指针时,我可能只修改字段。 So my question is now: How do I get the pointer to the data of the struct? 所以现在我的问题是: 如何获得指向结构数据的指针?

UPDATE: 更新:

I got it working using basically y := reflect.New(reflect.TypeOf(x)) so the values of y are settable now. 我基本上使用y := reflect.New(reflect.TypeOf(x))使它工作,所以y的值现在可以设置。 For an extensive example see this: https://gist.github.com/hvoecking/10772475 有关广泛的示例,请参阅: https//gist.github.com/hvoecking/10772475

You appear to be trying to modify the dynamic value stored inside an interface variable. 您似乎正在尝试修改存储在接口变量中的动态值。 The only operations you can perform on an interface variable are to get or set the dynamic value (operations that make copies), and to check the type of the stored value. 您可以对接口变量执行的唯一操作是获取或设置动态值(进行复制的操作),以及检查存储值的类型。

To understand why things are this way, imagine that there was such an operation and we had the following code: 要理解为什么会这样,想象有这样的操作,我们有以下代码:

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

What does ptr now represent? ptr现在代表什么? The language is free to reuse storage when assigning new values to an interface variable, so the the ptr might now point to the memory for the B value, which breaks the type safety of the language (with the current compilers storage is only guaranteed to be reused for small values, but the point remains). 在为接口变量分配新值时,该语言可以自由地重用存储,因此ptr现在可能指向B值的内存,这会破坏语言的类型安全性(当前编译器存储仅保证是重用小值,但重点仍然是)。

The only safe way to mutate the value stored in an interface is to copy the value out, then assign back a the modified version. 改变存储在接口中的值的唯一安全方法是复制值,然后返回修改后的版本。 For example: 例如:

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

The reflect package reflects these restrictions, so the reflect.Value representing the field of the dynamic value is considered read only. reflect包反映了这些限制,因此表示动态值字段的reflect.Value被认为是只读的。

You are able to set fields in your first example because the dynamic value for z is a *A pointer rather than the struct itself: this means the referenced struct can be modified. 您可以在第一个示例中设置字段,因为z的动态值是*A指针而不是结构本身:这意味着可以修改引用的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM