struct_copy.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package utils
  2. import (
  3. "errors"
  4. "reflect"
  5. )
  6. // check 检查参数
  7. func check(data interface{}) error {
  8. if reflect.TypeOf(data).Kind() != reflect.Ptr {
  9. return errors.New("param must be ptr")
  10. }
  11. if reflect.ValueOf(data).IsNil() {
  12. return errors.New("param can not be nil")
  13. }
  14. if reflect.TypeOf(data).Elem().Kind() == reflect.Ptr {
  15. return errors.New("param must be ptr")
  16. }
  17. return nil
  18. }
  19. // getFieldArray 获取结构体元素数组
  20. func getFieldArray(t reflect.Type) (ret []reflect.StructField) {
  21. for i := 0; i < t.NumField(); i++ {
  22. field := t.Field(i)
  23. ret = append(ret, field)
  24. }
  25. return ret
  26. }
  27. // FieldByTag 根据tag名(tagName)和tag值(tag)从结构体重获取元素
  28. // 如果tag或tagName为空,则根据元素名称获取元素
  29. func FieldByTag(value reflect.Value, name string, tag string, tagName string) reflect.Value {
  30. if tag == "" || tagName == "" {
  31. return value.FieldByName(name)
  32. }
  33. itype := value.Type()
  34. for i := 0; i < itype.NumField(); i++ {
  35. v := itype.Field(i)
  36. if v.Tag.Get(tagName) == tag {
  37. return value.FieldByIndex(v.Index)
  38. }
  39. }
  40. return reflect.Value{}
  41. }
  42. // subStructCopy copy结构体中的子结构体
  43. func subStructCopy(dst reflect.Value, src reflect.Value, tagName string) {
  44. fields := getFieldArray(src.Type())
  45. for _, v := range fields {
  46. // 获取元素
  47. srcf := FieldByTag(src, v.Name, v.Tag.Get(tagName), tagName)
  48. dstf := FieldByTag(dst, v.Name, v.Tag.Get(tagName), tagName)
  49. // 是否能赋值
  50. if dstf.CanSet() == false {
  51. continue
  52. }
  53. // 如果元素是结构体,递归
  54. if v.Type.Kind() == reflect.Struct {
  55. subStructCopy(dstf, srcf, tagName)
  56. continue
  57. }
  58. if dstf.Type() != srcf.Type() {
  59. // 源和目标类型不一致,基础类型为切片且元素都为结构体,进行切片拷贝
  60. if v.Type.Kind() == reflect.Slice &&
  61. dstf.Type().Kind() == reflect.Slice &&
  62. srcf.Type().Kind() == reflect.Slice &&
  63. dstf.Type().Elem().Kind() == reflect.Struct &&
  64. srcf.Type().Elem().Kind() == reflect.Struct {
  65. array := reflect.MakeSlice(dstf.Type(), 0, 0)
  66. for i := 0; i < srcf.Len(); i++ {
  67. item := reflect.New(dstf.Type().Elem())
  68. subStructCopy(item.Elem(), srcf.Index(i), tagName)
  69. array = reflect.Append(array, item.Elem())
  70. }
  71. dstf.Set(array)
  72. }
  73. continue
  74. }
  75. // 拷贝指针指向的数据
  76. if dstf.Kind() == reflect.Ptr && srcf.IsNil() == false {
  77. dstf.Set(reflect.New(dstf.Type().Elem()))
  78. dstf.Elem().Set(srcf.Elem())
  79. continue
  80. }
  81. // 普通数据拷贝
  82. dstf.Set(srcf)
  83. }
  84. }
  85. // StructCopy 根据tagName(如json)进行结构体拷贝
  86. // tagName为空,默认按结构体元素名进行拷贝
  87. func StructCopy(dst interface{}, src interface{}, tagName string) error {
  88. if err := check(dst); err != nil {
  89. return err
  90. }
  91. if err := check(src); err != nil {
  92. return err
  93. }
  94. srcv := reflect.ValueOf(src).Elem()
  95. dstv := reflect.ValueOf(dst).Elem()
  96. subStructCopy(dstv, srcv, tagName)
  97. return nil
  98. }