我正在尝试实现一种方法,该方法更改可以具有任意结构的对象中字段的值。当我有一个指向结构的指针时,字段的遍历是没有问题的。但是,当我有一个不包装指向结构的指针但包装结构本身的接口时,简而言之,我无法更改字段:
// 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
我已阅读《反射定律》,因此我知道只有在具有指向结构的指针时,才可以修改字段。现在我的问题是: 如何获取结构数据的指针?
更新:
我基本上使用它来工作,y := reflect.New(reflect.TypeOf(x))因此y现在可以设置的值。有关广泛的示例,请参见:https : //gist.github.com/hvoecking/10772475
y := reflect.New(reflect.TypeOf(x))
y
您似乎正在尝试修改存储在接口变量中的动态值。您可以对接口变量执行的唯一操作是获取或设置动态值(进行复制的操作),并检查存储值的类型。
要了解为什么事情是这样的,请想象有一个这样的操作,并且我们有以下代码:
var ptr *A = pointer_to_dynamic_value(x) x = B{...}
什么是ptr现在代表什么?在将新值分配给接口变量时,该语言可以自由地重用存储,因此ptr可能现在指向该B值的内存,这破坏了该语言的类型安全性(使用当前的编译器,只能保证将其重用用于小值,但重点仍然存在)。
ptr
B
更改存储在接口中的值的唯一安全方法是将值复制出来,然后分配回修改后的版本。例如:
a := x.(A) a.Str = "Bye" x = a
该reflect包装反映了这些限制,因此reflect.Value代表被视为只读动态值的字段。
reflect
reflect.Value
您可以在第一个示例中设置字段,因为的动态值z是*A指针而不是结构本身:这意味着可以修改引用的结构。
z
*A