19

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

Heye
  • 603
  • 6
  • 14

1 Answers1

10

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.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • 2
    Ah, I get it. My way around that problem would be (in order to support arbitrary structs) to create a new instance with the help of `y := reflect.New(reflect.TypeOf(x))` and copy all fields of `x` to the corresponding fields of `y`. – Heye Apr 14 '14 at 00:16
  • Thanks Heye, you saved me another hour of search. :) – Danyel Apr 09 '15 at 14:56
  • 2
    That makes perfect sense; but what is the reasoning for why you can't change a field inside a dynamic value, for example "x.(list).head = z" - since this doesn't create a dangling pointer. – WPWoodJr Feb 22 '18 at 20:25