mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-07 06:02:27 +08:00
feat: add ToInterface and CopyProperties
This commit is contained in:
@@ -278,44 +278,99 @@ func DeepClone(src interface{}) interface{} {
|
||||
return result.Interface()
|
||||
}
|
||||
|
||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
func CopyProperties(dst, src interface{}) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = errors.New(fmt.Sprintf("%v", e))
|
||||
}
|
||||
}()
|
||||
// // CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
// 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)
|
||||
// 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
|
||||
// }
|
||||
|
||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||
func CopyProperties(dst, src interface{}) error {
|
||||
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
|
||||
|
||||
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 {
|
||||
srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
||||
srcType = srcType.Elem()
|
||||
}
|
||||
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()
|
||||
|
||||
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)
|
||||
}
|
||||
bytes, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
|
||||
}
|
||||
err = json.Unmarshal(bytes, dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToInterface converts reflect value to its interface type.
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
|
||||
if v.IsValid() && v.CanInterface() {
|
||||
return v.Interface(), true
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return v.Bool(), true
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int(), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint(), true
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float(), true
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return v.Complex(), true
|
||||
case reflect.String:
|
||||
return v.String(), true
|
||||
case reflect.Ptr:
|
||||
return ToInterface(v.Elem())
|
||||
case reflect.Interface:
|
||||
return ToInterface(v.Elem())
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,49 +262,80 @@ func TestDeepClone(t *testing.T) {
|
||||
func TestCopyProperties(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||
|
||||
type Address struct {
|
||||
Country string
|
||||
ZipCode string
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
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.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)
|
||||
assert.Equal("001", indicatorVO.Id)
|
||||
assert.Equal("127.0.0.1", indicatorVO.Ip)
|
||||
assert.Equal(3, len(indicatorVO.Disk))
|
||||
}
|
||||
|
||||
func TestToInterface(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToInterface")
|
||||
|
||||
cases := []reflect.Value{
|
||||
reflect.ValueOf("abc"),
|
||||
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
|
||||
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
|
||||
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
|
||||
reflect.ValueOf(true), reflect.ValueOf(false),
|
||||
}
|
||||
|
||||
expected := []interface{}{
|
||||
"abc",
|
||||
0, int8(1), int16(-1), int32(123), int64(123),
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
float64(12.3), float32(12.3),
|
||||
true, false,
|
||||
}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual, _ := ToInterface(cases[i])
|
||||
assert.Equal(expected[i], actual)
|
||||
}
|
||||
|
||||
nilVal, ok := ToInterface(reflect.ValueOf(nil))
|
||||
assert.EqualValues(nil, nilVal)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ import (
|
||||
- [EncodeByte](#EncodeByte)
|
||||
- [DecodeByte](#DecodeByte)
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -501,3 +504,117 @@ func main() {
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<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>
|
||||
|
||||
```go
|
||||
func CopyProperties(dst, src interface{}) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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},
|
||||
}}
|
||||
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToInterface">ToInterface</span>
|
||||
|
||||
<p>Converts reflect value to its interface type.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -36,6 +36,8 @@ import (
|
||||
- [EncodeByte](#EncodeByte)
|
||||
- [DecodeByte](#DecodeByte)
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -501,3 +503,118 @@ func main() {
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CopyProperties(dst, src interface{}) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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},
|
||||
}}
|
||||
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToInterface">ToInterface</span>
|
||||
|
||||
<p>将反射值转换成对应的interface类型。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user