fix map to embedded struct
This commit is contained in:
43
copier.go
43
copier.go
@@ -146,16 +146,13 @@ func (c *copier) copySliceToSlice(dst, src reflect.Value, depth int) error {
|
|||||||
func (c *copier) copyToSlice(dst, src reflect.Value, depth int) error {
|
func (c *copier) copyToSlice(dst, src reflect.Value, depth int) error {
|
||||||
srcLen := src.Len()
|
srcLen := src.Len()
|
||||||
|
|
||||||
// 如果目标slice为空或长度不够,重新创建
|
|
||||||
if dst.IsNil() || dst.Len() < srcLen {
|
if dst.IsNil() || dst.Len() < srcLen {
|
||||||
newSlice := reflect.MakeSlice(dst.Type(), srcLen, srcLen)
|
newSlice := reflect.MakeSlice(dst.Type(), srcLen, srcLen)
|
||||||
dst.Set(newSlice)
|
dst.Set(newSlice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确定实际复制的元素数量
|
|
||||||
copyLen := min(dst.Len(), srcLen)
|
copyLen := min(dst.Len(), srcLen)
|
||||||
|
|
||||||
// 复制元素
|
|
||||||
for i := range copyLen {
|
for i := range copyLen {
|
||||||
if err := c.deepCopy(dst.Index(i), src.Index(i), depth+1); err != nil {
|
if err := c.deepCopy(dst.Index(i), src.Index(i), depth+1); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -191,7 +188,8 @@ func (c *copier) copyStruct2Map(dst, src reflect.Value, depth int) error {
|
|||||||
if sf.Field.Anonymous {
|
if sf.Field.Anonymous {
|
||||||
switch sf.Field.Type.Kind() {
|
switch sf.Field.Type.Kind() {
|
||||||
case reflect.Struct, reflect.Pointer:
|
case reflect.Struct, reflect.Pointer:
|
||||||
if err := c.deepCopy(dst, src.Field(sf.Index), depth+1); err != nil {
|
field := c.fieldByName(src, sf.Field.Name)
|
||||||
|
if err := c.deepCopy(dst, field, depth+1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,7 +204,7 @@ func (c *copier) copyStruct2Map(dst, src reflect.Value, depth int) error {
|
|||||||
|
|
||||||
name := c.getFieldName(sf.Field.Name, tag)
|
name := c.getFieldName(sf.Field.Name, tag)
|
||||||
|
|
||||||
sField := src.Field(sf.Index)
|
sField := c.fieldByName(src, sf.Field.Name)
|
||||||
|
|
||||||
if c.opt.ignoreEmpty && sField.IsZero() {
|
if c.opt.ignoreEmpty && sField.IsZero() {
|
||||||
continue
|
continue
|
||||||
@@ -240,15 +238,29 @@ func (c *copier) copyStruct2Map(dst, src reflect.Value, depth int) error {
|
|||||||
func (c *copier) copyMap(dst, src reflect.Value, depth int) error {
|
func (c *copier) copyMap(dst, src reflect.Value, depth int) error {
|
||||||
switch dst.Kind() {
|
switch dst.Kind() {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
return c.copyMap2Map(dst, src, depth)
|
return c.copyMapToMap(dst, src, depth)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return c.copyMapToStruct(dst, src, depth)
|
return c.copyMapToStruct(dst, src, depth)
|
||||||
|
case reflect.Pointer:
|
||||||
|
if dst.IsNil() {
|
||||||
|
elemType := dst.Type().Elem()
|
||||||
|
newPtr := reflect.New(elemType)
|
||||||
|
if err := c.deepCopy(newPtr.Elem(), src, depth+1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dst.Set(newPtr)
|
||||||
|
} else {
|
||||||
|
if err := c.deepCopy(dst.Elem(), src, depth+1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *copier) copyMap2Map(dst, src reflect.Value, depth int) error {
|
func (c *copier) copyMapToMap(dst, src reflect.Value, depth int) error {
|
||||||
if dst.IsNil() {
|
if dst.IsNil() {
|
||||||
dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len()))
|
dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len()))
|
||||||
}
|
}
|
||||||
@@ -302,7 +314,10 @@ func (c *copier) copyMapToStruct(dst, src reflect.Value, depth int) error {
|
|||||||
|
|
||||||
fields := c.deepFields(dst.Type())
|
fields := c.deepFields(dst.Type())
|
||||||
for _, sf := range fields {
|
for _, sf := range fields {
|
||||||
field := dst.Field(sf.Index)
|
if nestedAnonymousField(dst, sf.Field.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
field := dst.FieldByName(sf.Field.Name)
|
||||||
|
|
||||||
if !field.CanSet() {
|
if !field.CanSet() {
|
||||||
continue
|
continue
|
||||||
@@ -315,8 +330,13 @@ func (c *copier) copyMapToStruct(dst, src reflect.Value, depth int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name := sf.Field.Name
|
name := sf.Field.Name
|
||||||
|
var mapValue reflect.Value
|
||||||
|
if c.opt.caseSensitive {
|
||||||
|
mapValue = src.MapIndex(reflect.ValueOf(name))
|
||||||
|
} else {
|
||||||
|
mapValue = src.MapIndex(reflect.ValueOf(strings.ToLower(name)))
|
||||||
|
}
|
||||||
|
|
||||||
mapValue := src.MapIndex(reflect.ValueOf(name))
|
|
||||||
if !mapValue.IsValid() {
|
if !mapValue.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -592,7 +612,6 @@ type fieldsWrapper struct {
|
|||||||
type fieldWrapper struct {
|
type fieldWrapper struct {
|
||||||
Field reflect.StructField
|
Field reflect.StructField
|
||||||
Tag *tagOption
|
Tag *tagOption
|
||||||
Index int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var deepFieldsMap sync.Map
|
var deepFieldsMap sync.Map
|
||||||
@@ -634,9 +653,9 @@ func (c *copier) calculateDeepFields(reflectType reflect.Type) []fieldWrapper {
|
|||||||
|
|
||||||
if sf.Anonymous {
|
if sf.Anonymous {
|
||||||
res = append(res, c.deepFields(sf.Type)...)
|
res = append(res, c.deepFields(sf.Type)...)
|
||||||
|
} else {
|
||||||
|
res = append(res, fieldWrapper{Field: sf, Tag: tag})
|
||||||
}
|
}
|
||||||
|
|
||||||
res = append(res, fieldWrapper{Field: sf, Tag: tag, Index: i})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ func TestAnonymousStructToMapCopy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dst := person2{}
|
dst := person2{}
|
||||||
if err := Copy(&dst, src); err != nil {
|
if err := Copy(&dst, src, WithCaseSensitive()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,9 +174,11 @@ func TestMapToStructCopy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dst := person{}
|
dst := person{}
|
||||||
if err := Copy(&dst, src); err != nil {
|
if err := Copy(&dst, src, WithCaseSensitive()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Log(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMixMapToStruct(t *testing.T) {
|
func TestMixMapToStruct(t *testing.T) {
|
||||||
@@ -224,6 +226,8 @@ func TestMixMapToStruct(t *testing.T) {
|
|||||||
if err := Copy(&dst, src); err != nil {
|
if err := Copy(&dst, src); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Log(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMapCopy(b *testing.B) {
|
func BenchmarkMapCopy(b *testing.B) {
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ func TestDeepFileds(t *testing.T) {
|
|||||||
copier := newCopier()
|
copier := newCopier()
|
||||||
wrapper := copier.deepFields(typ)
|
wrapper := copier.deepFields(typ)
|
||||||
for _, v := range wrapper {
|
for _, v := range wrapper {
|
||||||
t.Log(v, v.Index)
|
t.Log(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user