Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining an addressable copy of a reflect.Value

Tags:

reflection

go

I want to add marshalling/unmarshalling to types that I accept, in a way similar JSON custom encoding/decoding. I have it all working great when the type implements a Marshal method (value receiver) and Unmarshal method (pointer receiver).

The Unmarshal method must obviously use a pointer receiver so that the new value is saved. I have been told that a Marshal method using a pointer (not value) receiver should also be allowed. The trouble with this is I am using a reflect.Value which is not always addressable.

Here's an edited extract of the code which panics:

  var v reflect.Value // passed in parameter

  t := v.Type()
  pt := reflect.TypeOf(reflect.New(t).Interface())

  if t.Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()) {
    str, err = v.Interface().(Marshaler).MarshalXXX()
    // ... value receiver WORKS FINE

  } else if pt.Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()) {
    str, err = v.Addr().Interface().(Marshaler).MarshalXXX()
    // ptr receiver gives PANIC value is not addressable

I tried creating a copy of v, but the copy is also not addressable which makes no sense to me:

    tmp := reflect.New(v.Type())
    tmp.Addr().Set(v)
    str, err = tmp.Interface().(Marshaler).MarshalXXX()

In case I have not explained this well here is an example on the Go Playground for you to try:

Also while I am here: Is there a better way to get the type of a pointer to a the type than in the assignment to pt above?

like image 657
AJR Avatar asked Sep 01 '25 20:09

AJR


1 Answers

I found the answer. The problem was I was using Addr instead of Elem. Though that begs the question why Set worked, since the panic did not occur till the following line.

In summary, to create an addressable copy of a reflect.Value v do this:

  tmp := reflect.New(v.Type()) // create zero value of same type as v
  tmp.Elem().Set(v)

Please forgive me asking prematurely, but I had already spent 4 hours trying to solve the problem. For completeness here is the fix to my Go playground code in the question.

like image 187
AJR Avatar answered Sep 03 '25 21:09

AJR