mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
fix: refact CopyProperties
This commit is contained in:
@@ -11,11 +11,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/structs"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToBool convert string to boolean.
|
// ToBool convert string to boolean.
|
||||||
@@ -319,43 +320,29 @@ func DeepClone[T any](src T) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
// Play: https://go.dev/play/p/FOVY3XJL-6B
|
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||||
func CopyProperties[T, U any](dst T, src U) (err error) {
|
// Play: todo
|
||||||
defer func() {
|
func CopyProperties[T, U any](dst T, src U) error {
|
||||||
if e := recover(); e != nil {
|
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
|
||||||
err = fmt.Errorf("%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 {
|
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||||
return errors.New("CopyProperties: param dst should be struct pointer")
|
return errors.New("CopyProperties: parameter dst should be struct pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
if srcType.Kind() == reflect.Ptr {
|
if srcType.Kind() == reflect.Ptr {
|
||||||
srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
srcType = srcType.Elem()
|
||||||
}
|
}
|
||||||
if srcType.Kind() != reflect.Struct {
|
if srcType.Kind() != reflect.Struct {
|
||||||
return errors.New("CopyProperties: param src should be a struct or struct pointer")
|
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
bytes, err := json.Marshal(src)
|
||||||
|
if err != nil {
|
||||||
propertyNums := dstType.NumField()
|
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
|
||||||
|
}
|
||||||
for i := 0; i < propertyNums; i++ {
|
err = json.Unmarshal(bytes, dst)
|
||||||
property := dstType.Field(i)
|
if err != nil {
|
||||||
propertyValue := srcValue.FieldByName(property.Name)
|
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
|
||||||
|
|
||||||
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if dstValue.Field(i).CanSet() {
|
|
||||||
dstValue.Field(i).Set(propertyValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -297,49 +297,55 @@ func ExampleDeepClone() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleCopyProperties() {
|
func ExampleCopyProperties() {
|
||||||
type Address struct {
|
type Disk struct {
|
||||||
Country string
|
Name string `json:"name"`
|
||||||
ZipCode string
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type DiskVO struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Age int
|
Total string `json:"total"`
|
||||||
Role string
|
Used string `json:"used"`
|
||||||
Addr Address
|
Percent float64 `json:"percent"`
|
||||||
Hobbys []string
|
|
||||||
salary int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Employee struct {
|
type Indicator struct {
|
||||||
Name string
|
Id string `json:"id"`
|
||||||
Age int
|
Ip string `json:"ip"`
|
||||||
Role string
|
UpTime string `json:"upTime"`
|
||||||
Addr Address
|
LoadAvg string `json:"loadAvg"`
|
||||||
Hobbys []string
|
Cpu int `json:"cpu"`
|
||||||
salary int
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
employee1 := Employee{}
|
Ip string `json:"ip"`
|
||||||
err := CopyProperties(&employee1, &user)
|
UpTime string `json:"upTime"`
|
||||||
if err != nil {
|
LoadAvg string `json:"loadAvg"`
|
||||||
return
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
}
|
}
|
||||||
|
|
||||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
err = CopyProperties(&employee2, &user)
|
indicatorVO := IndicatorVO{}
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(employee1)
|
CopyProperties(&indicatorVO, indicator)
|
||||||
fmt.Println(employee2)
|
|
||||||
|
fmt.Println(indicatorVO.Id)
|
||||||
|
fmt.Println(indicatorVO.Ip)
|
||||||
|
fmt.Println(len(indicatorVO.Disk))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// {user001 10 Admin {CN 001} [a b] 0}
|
// 001
|
||||||
// {user001 10 Admin {CN 001} [a b] 500}
|
// 127.0.0.1
|
||||||
|
// 3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,49 +320,51 @@ func TestDeepClone(t *testing.T) {
|
|||||||
func TestCopyProperties(t *testing.T) {
|
func TestCopyProperties(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCopyProperties")
|
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||||
|
|
||||||
type Address struct {
|
type Disk struct {
|
||||||
Country string
|
Name string `json:"name"`
|
||||||
ZipCode string
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type DiskVO struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Age int
|
Total string `json:"total"`
|
||||||
Role string
|
Used string `json:"used"`
|
||||||
Addr Address
|
Percent float64 `json:"percent"`
|
||||||
Hobbys []string
|
|
||||||
salary int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Employee struct {
|
type Indicator struct {
|
||||||
Name string
|
Id string `json:"id"`
|
||||||
Age int
|
Ip string `json:"ip"`
|
||||||
Role string
|
UpTime string `json:"upTime"`
|
||||||
Addr Address
|
LoadAvg string `json:"loadAvg"`
|
||||||
Hobbys []string
|
Cpu int `json:"cpu"`
|
||||||
salary int
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
employee1 := Employee{}
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
err := CopyProperties(&employee1, &user)
|
indicatorVO := IndicatorVO{}
|
||||||
|
|
||||||
|
err := CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
assert.Equal("user001", employee1.Name)
|
assert.Equal("001", indicatorVO.Id)
|
||||||
assert.Equal("Admin", employee1.Role)
|
assert.Equal("127.0.0.1", indicatorVO.Ip)
|
||||||
assert.Equal("CN", employee1.Addr.Country)
|
assert.Equal(3, len(indicatorVO.Disk))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -697,7 +697,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="CopyProperties">CopyProperties</span>
|
### <span id="CopyProperties">CopyProperties</span>
|
||||||
|
|
||||||
<p>Copies each field from the source struct into the destination struct.</p>
|
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -716,44 +716,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
type Address struct {
|
type Disk struct {
|
||||||
Country string
|
Name string `json:"name"`
|
||||||
ZipCode string
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type DiskVO struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Age int
|
Total string `json:"total"`
|
||||||
Role string
|
Used string `json:"used"`
|
||||||
Addr Address
|
Percent float64 `json:"percent"`
|
||||||
Hobbys []string
|
|
||||||
salary int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Employee struct {
|
type Indicator struct {
|
||||||
Name string
|
Id string `json:"id"`
|
||||||
Age int
|
Ip string `json:"ip"`
|
||||||
Role string
|
UpTime string `json:"upTime"`
|
||||||
Addr Address
|
LoadAvg string `json:"loadAvg"`
|
||||||
Hobbys []string
|
Cpu int `json:"cpu"`
|
||||||
salary int
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
employee1 := Employee{}
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
CopyProperties(&employee1, &user)
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
indicatorVO := IndicatorVO{}
|
||||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
|
||||||
|
|
||||||
CopyProperties(&employee2, &user)
|
CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
fmt.Println(employee1)
|
fmt.Println(indicatorVO.Id)
|
||||||
fmt.Println(employee2)
|
fmt.Println(indicatorVO.Ip)
|
||||||
|
fmt.Println(len(indicatorVO.Disk))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// {user001 10 Admin {CN 001} [a b] 0}
|
// 001
|
||||||
// {user001 10 Admin {CN 001} [a b] 500}
|
// 127.0.0.1
|
||||||
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -696,7 +696,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="CopyProperties">CopyProperties</span>
|
### <span id="CopyProperties">CopyProperties</span>
|
||||||
|
|
||||||
<p>拷贝不同结构体之间的同名字段。</p>
|
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -715,44 +715,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
type Address struct {
|
type Disk struct {
|
||||||
Country string
|
Name string `json:"name"`
|
||||||
ZipCode string
|
Total string `json:"total"`
|
||||||
|
Used string `json:"used"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type DiskVO struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Age int
|
Total string `json:"total"`
|
||||||
Role string
|
Used string `json:"used"`
|
||||||
Addr Address
|
Percent float64 `json:"percent"`
|
||||||
Hobbys []string
|
|
||||||
salary int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Employee struct {
|
type Indicator struct {
|
||||||
Name string
|
Id string `json:"id"`
|
||||||
Age int
|
Ip string `json:"ip"`
|
||||||
Role string
|
UpTime string `json:"upTime"`
|
||||||
Addr Address
|
LoadAvg string `json:"loadAvg"`
|
||||||
Hobbys []string
|
Cpu int `json:"cpu"`
|
||||||
salary int
|
Disk []Disk `json:"disk"`
|
||||||
|
Stop chan bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
type IndicatorVO struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
UpTime string `json:"upTime"`
|
||||||
|
LoadAvg string `json:"loadAvg"`
|
||||||
|
Cpu int64 `json:"cpu"`
|
||||||
|
Disk []DiskVO `json:"disk"`
|
||||||
|
}
|
||||||
|
|
||||||
employee1 := Employee{}
|
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||||
CopyProperties(&employee1, &user)
|
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||||
|
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||||
|
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||||
|
}}
|
||||||
|
|
||||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
indicatorVO := IndicatorVO{}
|
||||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
|
||||||
|
|
||||||
CopyProperties(&employee2, &user)
|
CopyProperties(&indicatorVO, indicator)
|
||||||
|
|
||||||
fmt.Println(employee1)
|
fmt.Println(indicatorVO.Id)
|
||||||
fmt.Println(employee2)
|
fmt.Println(indicatorVO.Ip)
|
||||||
|
fmt.Println(len(indicatorVO.Disk))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// {user001 10 Admin {CN 001} [a b] 0}
|
// 001
|
||||||
// {user001 10 Admin {CN 001} [a b] 500}
|
// 127.0.0.1
|
||||||
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user