douchou8935 2014-04-13 13:46
浏览 58
已采纳

Golang反射:无法设置包装结构的界面字段

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

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. For an extensive example see this: https://gist.github.com/hvoecking/10772475

  • 写回答

1条回答 默认 最新

  • duanchi0883649 2014-04-13 16:06
    关注

    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? 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).

    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.

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办