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

Hey*_*eye 14 reflection struct pointers interface go

我正在尝试实现一个方法,该方法可以更改可以具有任意结构的对象中的字段值.当我有一个指向结构的指针时,字段的转换没有问题.但是,当我的接口没有包装指向结构的指针但结构本身时,我无法改变字段,简而言之:

// 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())
Run Code Online (Sandbox Code Playgroud)

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

我已经阅读了反射法则,所以我知道当我有一个指向结构的指针时,我可能只修改字段.所以现在我的问题是:如何获得指向结构数据的指针?

更新:

我基本上使用它,y := reflect.New(reflect.TypeOf(x))所以y现在可以设置值.有关广泛的示例,请参阅:https://gist.github.com/hvoecking/10772475

Jam*_*dge 8

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

要理解为什么会这样,想象有这样的操作,我们有以下代码:

var ptr *A = pointer_to_dynamic_value(x)
x = B{...}
Run Code Online (Sandbox Code Playgroud)

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

改变存储在接口中的值的唯一安全方法是复制值,然后返回修改后的版本.例如:

a := x.(A)
a.Str = "Bye"
x = a
Run Code Online (Sandbox Code Playgroud)

reflect包装反映了这些限制,因此reflect.Value代表了动态值的字段被视为只读.

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

  • 啊,我明白了。我解决这个问题的方法是(为了支持任意结构)在 `y := Reflect.New(reflect.TypeOf(x))` 的帮助下创建一个新实例,并将 `x` 的所有字段复制到`y` 的对应字段。 (2认同)
  • 这是完全有道理的;但是为什么不能更改动态值中的字段的原因是什么,例如“x.(list).head = z” - 因为这不会创建悬空指针。 (2认同)