diff --git a/copier.go b/copier.go index 286ddb6..a933d62 100644 --- a/copier.go +++ b/copier.go @@ -102,7 +102,16 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) ) if !to.CanAddr() { - return ErrInvalidCopyDestination + toPtr := preIndirect(reflect.ValueOf(toValue)) + if !toPtr.CanSet() { + return ErrInvalidCopyDestination + } + to = reflect.New(toPtr.Type().Elem()) + toPtr.Set(to) + // reindirect + if to = indirect(reflect.ValueOf(toValue)); !to.CanAddr() { + return ErrInvalidCopyDestination + } } // Return is from value is invalid @@ -433,6 +442,16 @@ func deepFields(reflectType reflect.Type) []reflect.StructField { return res } +func preIndirect(reflectValue reflect.Value) reflect.Value { + for reflectValue.Kind() == reflect.Ptr { + if !reflectValue.Elem().CanAddr() { + break + } + reflectValue = reflectValue.Elem() + } + return reflectValue +} + func indirect(reflectValue reflect.Value) reflect.Value { for reflectValue.Kind() == reflect.Ptr { reflectValue = reflectValue.Elem() diff --git a/copier_test.go b/copier_test.go index 4cc85b4..f1fdb70 100644 --- a/copier_test.go +++ b/copier_test.go @@ -1666,3 +1666,18 @@ func TestSqlNullFiled(t *testing.T) { t.Errorf("to (%v) value should equal from (%v) value", to.MkExpiryDateType, from.MkExpiryDateType.Int32) } } + +func TestCopy(t *testing.T) { + now := time.Now() + age := int32(28) + src := &User{ + Age: 14, + Name: "tom", + Birthday: &now, + FakeAge: &age, + Notes: []string{"hello"}, + } + var tar *User + err := copier.Copy(&tar, src) + fmt.Println(err, tar, reflect.DeepEqual(src, tar)) +}