package utils import ( "errors" "reflect" ) func DeepFields(ifaceType reflect.Type) []reflect.StructField { var fields []reflect.StructField for i := 0; i < ifaceType.NumField(); i++ { v := ifaceType.Field(i) if v.Anonymous && v.Type.Kind() == reflect.Struct { fields = append(fields, DeepFields(v.Type)...) } else { fields = append(fields, v) } } return fields } func StructCopy(DstStructPtr interface{}, SrcStructPtr interface{}) error { srcv := reflect.ValueOf(SrcStructPtr) dstv := reflect.ValueOf(DstStructPtr) srct := reflect.TypeOf(SrcStructPtr) dstt := reflect.TypeOf(DstStructPtr) if srct.Kind() != reflect.Ptr || dstt.Kind() != reflect.Ptr || srct.Elem().Kind() == reflect.Ptr || dstt.Elem().Kind() == reflect.Ptr { return errors.New("Fatal error:type of parameters must be Ptr of value") } if srcv.IsNil() || dstv.IsNil() { return errors.New("Fatal error:value of parameters should not be nil") } srcV := srcv.Elem() dstV := dstv.Elem() srcfields := DeepFields(reflect.ValueOf(SrcStructPtr).Elem().Type()) for _, v := range srcfields { if v.Anonymous { continue } dst := dstV.FieldByName(v.Name) src := srcV.FieldByName(v.Name) if !dst.IsValid() { continue } if src.Type() == dst.Type() && dst.CanSet() { dst.Set(src) continue } if src.Kind() == reflect.Ptr && !src.IsNil() && src.Type().Elem() == dst.Type() { dst.Set(src.Elem()) continue } if dst.Kind() == reflect.Ptr && dst.Type().Elem() == src.Type() { dst.Set(reflect.New(src.Type())) dst.Elem().Set(src) continue } } return nil } func FieldByTag(value reflect.Value, tag string, tagName string) reflect.Value { itype := value.Type() for i := 0; i < itype.NumField(); i++ { v := itype.Field(i) if v.Tag.Get(tagName) == tag && tag != "" { return value.FieldByIndex(v.Index) } } return reflect.Value{} } func StructCopyByTag(DstStructPtr interface{}, SrcStructPtr interface{}, tagName string) error { srcv := reflect.ValueOf(SrcStructPtr) dstv := reflect.ValueOf(DstStructPtr) srct := reflect.TypeOf(SrcStructPtr) dstt := reflect.TypeOf(DstStructPtr) if srct.Kind() != reflect.Ptr || dstt.Kind() != reflect.Ptr || srct.Elem().Kind() == reflect.Ptr || dstt.Elem().Kind() == reflect.Ptr { return errors.New("Fatal error:type of parameters must be Ptr of value") } if srcv.IsNil() || dstv.IsNil() { return errors.New("Fatal error:value of parameters should not be nil") } srcV := srcv.Elem() dstV := dstv.Elem() srcfields := DeepFields(reflect.ValueOf(SrcStructPtr).Elem().Type()) for _, v := range srcfields { if v.Anonymous { continue } dst := FieldByTag(dstV, v.Tag.Get(tagName), tagName) src := FieldByTag(srcV, v.Tag.Get(tagName), tagName) if !dst.IsValid() { continue } if src.Type() == dst.Type() && dst.CanSet() { dst.Set(src) continue } if src.Kind() == reflect.Ptr && !src.IsNil() && src.Type().Elem() == dst.Type() { dst.Set(src.Elem()) continue } if dst.Kind() == reflect.Ptr && dst.Type().Elem() == src.Type() { dst.Set(reflect.New(src.Type())) dst.Elem().Set(src) continue } } return nil }