mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-12 08:42:29 +08:00
feat: add CopyProperties for merge properties between structs
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -340,3 +341,46 @@ func DeepClone[T any](src T) T {
|
|||||||
|
|
||||||
return result.Interface().(T)
|
return result.Interface().(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
|
// Play: todo
|
||||||
|
func CopyProperties(dst, src interface{}) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
err = errors.New(fmt.Sprintf("%v", e))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
|
||||||
|
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
|
||||||
|
|
||||||
|
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||||
|
return errors.New("CopyProperties: param dst should be struct pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcType.Kind() == reflect.Ptr {
|
||||||
|
srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
||||||
|
}
|
||||||
|
if srcType.Kind() != reflect.Struct {
|
||||||
|
return errors.New("CopyProperties: param src should be a struct or struct pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
||||||
|
|
||||||
|
propertyNums := dstType.NumField()
|
||||||
|
|
||||||
|
for i := 0; i < propertyNums; i++ {
|
||||||
|
property := dstType.Field(i)
|
||||||
|
propertyValue := srcValue.FieldByName(property.Name)
|
||||||
|
|
||||||
|
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if dstValue.Field(i).CanSet() {
|
||||||
|
dstValue.Field(i).Set(propertyValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -298,3 +298,53 @@ func TestDeepClone(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCopyProperties(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
Country string
|
||||||
|
ZipCode string
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Role string
|
||||||
|
Addr Address
|
||||||
|
Hobbys []string
|
||||||
|
salary int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Employee struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Role string
|
||||||
|
Addr Address
|
||||||
|
Hobbys []string
|
||||||
|
salary int
|
||||||
|
}
|
||||||
|
|
||||||
|
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||||
|
|
||||||
|
employee1 := Employee{}
|
||||||
|
|
||||||
|
err := CopyProperties(&employee1, &user)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("user001", employee1.Name)
|
||||||
|
assert.Equal("Admin", employee1.Role)
|
||||||
|
assert.Equal("CN", employee1.Addr.Country)
|
||||||
|
assert.Equal(0, employee1.salary)
|
||||||
|
|
||||||
|
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||||
|
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||||
|
|
||||||
|
err = CopyProperties(&employee2, &user)
|
||||||
|
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("user001", employee2.Name)
|
||||||
|
assert.Equal("Admin", employee2.Role)
|
||||||
|
assert.Equal("CN", employee2.Addr.Country)
|
||||||
|
assert.Equal(500, employee2.salary)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user