我试图实现一个方法来改变可以具有任意结构的对象中的字段的值.当我有一个指向一个结构体的指针时,字段的转换就没有问题.但是当我有一个接口不包含指向结构体的指针但结构本身时,我无法设法更改这些字段:简而言之
// 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
您似乎试图修改存储在接口变量中的动态值.您可以在接口变量上执行的唯一操作是获取或设置动态值(复制操作),并检查存储值的类型.
为了理解为什么这样做,想象有一个这样的操作,我们有以下代码:
var ptr *A = pointer_to_dynamic_value(x) x = B{...}
ptr现在代表什么?当向接口变量分配新值时,该语言可以自由地重用存储,因此ptr现在可以指向B值的内存,这会破坏语言的类型安全性(目前的编译器存储仅保证为重复使用小价值,但依然存在).
将存储在界面中的值进行变异的唯一安全方式是将值复制出来,然后分配修改后的版本.例如:
a := x.(A) a.Str = "Bye" x = a
反射包反映了这些限制,因此表示动态值字段的reflect.Value被认为是只读的.
您可以在第一个示例中设置字段,因为z的动态值是* A指针而不是struct本身:这意味着可以修改引用的结构体.