lundi 11 avril 2022

Obtaining an addressable copy of a reflect.Value

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?





Aucun commentaire:

Enregistrer un commentaire