jeudi 11 juin 2020

Set struct field of pointer type

The task is pretty simple. I have struct for model Foo, and one for it's representation:

type Foo struct {
  FooId string
  Bar   string
  Baz   *string
  Salt  int64
}

type FooView struct {
  FooId *string `json: "foo_id"`
  Bar   *string `json: "bar"`
  Baz   *string `json: "baz"`
}

As you may see, there is Salt field which I want to hide, change JSON field names, and do all the fields optional. The target method should fill FooView using Foo like this:

func MirrorFoo(foo Foo) (*FooView, error) {
  return &FooView{
    FooId: &foo.FooId,
    Bar:   &foo.Bar,
    Baz:   foo.Baz,
  }, nil
}

And now, I want to do the same with Go reflect:

func Mirror(src interface{}, dstType reflect.Type) (interface{}, error) {
  zeroValue := reflect.Value{}
  srcValue := reflect.ValueOf(src)
  srcType := srcValue.Type()
  dstValue := reflect.New(dstType)
  dstValueElem := dstValue.Elem()
  for i := 0; i < srcType.NumField(); i++ {
    srcTypeField := srcType.Field(i)
    srcValueField := srcValue.FieldByName(srcTypeField.Name)
    dstField := dstValueElem.FieldByName(srcTypeField.Name)

    // if current source field exists in destination type
    if dstField != zeroValue {
      srcValueField := srcValue.Field(i)
      if dstField.Kind() == reflect.Ptr && srcValueField.Kind() != reflect.Ptr {

        panic("???")

      } else {
        dstField.Set(srcValueField)
      }
    }
  }
  return dstValue.Interface(), nil
}

This code works fine when FooId is uuid.UUID in both types, but it fails when source is uuid.UUID and destination is *uuid.UUID, and now do not know how to overcome this.

Somehow I need to do analog of dstField.Set(reflect.ValueOf(&uuid.UUID{}...)) bit everything I've tried does not works. Any ideas?





Aucun commentaire:

Enregistrer un commentaire