package copier import ( "fmt" "reflect" "slices" "strconv" "strings" "time" ) func (c *copier) copySliceOrArray(dst, src reflect.Value, depth int) error { switch dst.Kind() { case reflect.Slice, reflect.Array: return c.copySliceToSlice(dst, src, depth) default: return ErrNotSupported(src.Type(), dst.Type()) } } func (c *copier) copyStructToSlice(dst, src reflect.Value, depth int) error { if dst.Kind() != reflect.Slice { return ErrNotSupported(src.Type(), dst.Type()) } // 创建新的slice,长度+1 dstLen := dst.Len() newSlice := reflect.MakeSlice(dst.Type(), dstLen+1, dstLen+1) // 复制原有元素 for i := range dstLen { if err := c.deepCopy(newSlice.Index(i), dst.Index(i), depth+1); err != nil { return err } } // 追加新元素(结构体) elem := newSlice.Index(dstLen) // 如果 slice 元素是指针类型,需要先创建实例 if elem.Kind() == reflect.Pointer { if elem.IsNil() { elem.Set(reflect.New(elem.Type().Elem())) } elem = elem.Elem() } if err := c.deepCopy(elem, src, depth+1); err != nil { return err } dst.Set(newSlice) return nil } func (c *copier) copySliceToSlice(dst, src reflect.Value, depth int) error { if dst.Kind() == reflect.Array { return c.copyToArray(dst, src, depth) } return c.copyToSlice(dst, src, depth) } func (c *copier) copyToSlice(dst, src reflect.Value, depth int) error { srcLen := src.Len() dstLen := dst.Len() // 创建新 slice,保留原有元素 + 追加 src 元素 newLen := dstLen + srcLen newSlice := reflect.MakeSlice(dst.Type(), newLen, newLen) // 复制原有元素 for i := range dstLen { if err := c.deepCopy(newSlice.Index(i), dst.Index(i), depth+1); err != nil { return err } } // 追加 src 元素 for i := range srcLen { if err := c.deepCopy(newSlice.Index(dstLen+i), src.Index(i), depth+1); err != nil { return err } } dst.Set(newSlice) return nil } func (c *copier) copyToArray(dst, src reflect.Value, depth int) error { srcLen := src.Len() dstLen := dst.Len() // 取较小长度 copyLen := min(dstLen, srcLen) for i := range copyLen { if err := c.deepCopy(dst.Index(i), src.Index(i), depth+1); err != nil { return err } } return nil } func (c *copier) copyStructToMap(dst, src reflect.Value, depth int) error { if dst.IsNil() { dst.Set(reflect.MakeMapWithSize(dst.Type(), src.NumField())) } fields := c.deepFields(src.Type()) for _, sf := range fields { if sf.Field.Anonymous { switch sf.Field.Type.Kind() { case reflect.Struct, reflect.Pointer: field := c.fieldByName(src, sf.Field.Name) if err := c.deepCopy(dst, field, depth+1); err != nil { return err } } continue } tag := parseTag(sf.Field.Tag.Get(c.opt.tagName)) if tag.Contains(tagIgnore) { continue } name := c.getFieldName(sf.Field.Name, tag) sField := c.fieldByName(src, sf.Field.Name) if c.opt.ignoreEmpty && sField.IsZero() { continue } var copiedValue reflect.Value if isTimeType(sField.Type()) { copiedValue = reflect.New(sField.Type()).Elem() if err := c.copyTime(copiedValue, sField); err != nil { return err } } else if sField.Kind() == reflect.Struct { copiedValue = reflect.ValueOf(make(map[string]any)) sField = indirect(sField) if err := c.deepCopy(copiedValue, sField, depth+1); err != nil { return err } } else { copiedValue = sField } dst.SetMapIndex(reflect.ValueOf(name), copiedValue) } return nil } func (c *copier) copyMap(dst, src reflect.Value, depth int) error { switch dst.Kind() { case reflect.Map: return c.copyMapToMap(dst, src, depth) case reflect.Struct: return c.copyMapToStruct(dst, src, depth) case reflect.Pointer: if dst.IsNil() { elemType := dst.Type().Elem() newPtr := reflect.New(elemType) if err := c.deepCopy(newPtr.Elem(), src, depth+1); err != nil { return err } dst.Set(newPtr) } else { if err := c.deepCopy(dst.Elem(), src, depth+1); err != nil { return err } } return nil default: return ErrNotSupported(src.Type(), dst.Type()) } } func (c *copier) copyMapToMap(dst, src reflect.Value, depth int) error { if dst.IsNil() { dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len())) } dstType, _ := indirectType(dst.Type()) iter := src.MapRange() for iter.Next() { key := iter.Key() value := iter.Value() if c.opt.ignoreEmpty && value.IsZero() { continue } if key.Kind() == reflect.Interface { key = key.Elem() } if name, ok := key.Interface().(string); ok { fieldName := c.getFieldName(name, nil) key = reflect.ValueOf(fieldName) } copiedValue := c.prepareMapValue(dstType.Elem(), value) if err := c.deepCopy(copiedValue, value, depth+1); err != nil { return err } dst.SetMapIndex(key, copiedValue) } return nil } func (c *copier) prepareMapValue(elemType reflect.Type, value reflect.Value) reflect.Value { if elemType.Kind() == reflect.Interface { if value.Kind() == reflect.Interface { return reflect.New(value.Elem().Type()).Elem() } return reflect.New(value.Type()).Elem() } return reflect.New(elemType).Elem() } func (c *copier) copyMapToStruct(dst, src reflect.Value, depth int) error { fields := c.deepFields(dst.Type()) for _, sf := range fields { if nestedAnonymousField(dst, sf.Field.Name) { continue } field := dst.FieldByName(sf.Field.Name) if !field.CanSet() { continue } if sf.Field.Anonymous { if err := c.deepCopy(field, src, depth+1); err != nil { return err } } name := sf.Field.Name var mapValue reflect.Value if c.opt.caseSensitive { mapValue = src.MapIndex(reflect.ValueOf(name)) } else { // fix: 忽略大小写查询 mapValue = src.MapIndex(reflect.ValueOf(strings.ToLower(name))) } if !mapValue.IsValid() { continue } if mapValue.Kind() == reflect.Interface { mapValue = mapValue.Elem() } if err := c.deepCopy(field, mapValue, depth+1); err != nil { return err } } return nil } func (c *copier) copyStruct(dst, src reflect.Value, depth int) error { switch dst.Kind() { case reflect.Struct: return c.copyStructToStruct(dst, src, depth) case reflect.Map: return c.copyStructToMap(dst, src, depth) case reflect.Slice: // 只有当 src 不是 struct 时才调用 copyStructToSlice // 否则应该将 src struct 追加到 dst slice if src.Kind() == reflect.Struct { return c.copyStructToSlice(dst, src, depth) } return ErrNotSupported(src.Type(), dst.Type()) default: return ErrNotSupported(src.Type(), dst.Type()) } } func (c *copier) copyStructToStruct(dst, src reflect.Value, depth int) error { if _, ok := src.Interface().(time.Time); ok && src.Type().AssignableTo(dst.Type()) { dst.Set(src) return nil } srcFields := c.deepFields(src.Type()) dstFields := c.deepFields(dst.Type()) for _, sf := range dstFields { _ = sf } for _, sf := range srcFields { name := c.getFieldName(sf.Field.Name, sf.Tag) sField := src.FieldByName(sf.Field.Name) // 是否忽略该字段 if c.ignore(sField, name, name, sf.Tag) { continue } if nestedAnonymousField(dst, name) { continue } dstValue := c.fieldByName(dst, name) if !dstValue.IsValid() { var toMethod reflect.Value if dst.CanAddr() { toMethod = dst.Addr().MethodByName(name) } else { toMethod = dst.MethodByName(name) } if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && toMethod.Type().In(0) == sField.Type() { toMethod.Call([]reflect.Value{sField}) } continue } if c.isCircularRefs(dstValue) { continue } if ok, err := c.lookupAndCopyWithConverter(dstValue, sField, name); err != nil { return err } else if ok { continue } if err := c.deepCopy(dstValue, sField, depth+1); err != nil { return err } } return nil } func (c *copier) copyInterface(dst, src reflect.Value, depth int) error { if src.IsNil() { return nil } srcElem := src.Elem() if dst.Kind() == reflect.Interface { newValue := reflect.New(srcElem.Type()).Elem() if err := c.deepCopy(newValue, srcElem, depth+1); err != nil { return err } dst.Set(newValue) return nil } return c.deepCopy(dst, srcElem, depth+1) } func (c *copier) copyPointer(dst, src reflect.Value, depth int) error { if src.IsNil() { return nil } srcElem := indirect(src) if dst.Kind() == reflect.Pointer { if dst.IsNil() { dst.Set(reflect.New(dst.Type().Elem())) } return c.deepCopy(dst.Elem(), srcElem, depth+1) } return c.deepCopy(dst, srcElem, depth+1) } func (c *copier) copyBasic(dst, src reflect.Value) error { if !src.IsValid() { return ErrInvalidCopyFrom } src = indirect(src) dst = ensureSettable(dst) if src.Type().AssignableTo(dst.Type()) { dst.Set(src) return nil } if src.Type().ConvertibleTo(dst.Type()) { dst.Set(src.Convert(dst.Type())) return nil } switch dst.Kind() { case reflect.String: return c.setString(dst, src) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return c.setInt(dst, src) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return c.setUint(dst, src) case reflect.Float32, reflect.Float64: return c.setFloat(dst, src) case reflect.Bool: return c.setBool(dst, src) default: return ErrNotSupported(src.Type(), dst.Type()) } } func ensureSettable(v reflect.Value) reflect.Value { if v.Kind() == reflect.Pointer && v.IsNil() && v.CanSet() { v.Set(reflect.New(v.Type().Elem())) return v.Elem() } return v } func (c *copier) setString(dst, src reflect.Value) error { switch src.Kind() { case reflect.String: dst.SetString(src.String()) case reflect.Slice: if src.Type().Elem().Kind() == reflect.Uint8 { dst.SetString(string(src.Bytes())) return nil } fallthrough default: dst.SetString(fmt.Sprintf("%v", src.Interface())) } return nil } func (c *copier) setInt(dst, src reflect.Value) error { switch src.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.SetInt(src.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.SetInt(int64(src.Uint())) case reflect.Float32, reflect.Float64: dst.SetInt(int64(src.Float())) default: return ErrNotSupported(src.Type(), dst.Type()) } return nil } func (c *copier) setUint(dst, src reflect.Value) error { switch src.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.SetUint(uint64(src.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.SetUint(src.Uint()) case reflect.Float32, reflect.Float64: dst.SetUint(uint64(src.Float())) case reflect.String: if i, err := strconv.ParseUint(src.String(), 10, 64); err == nil { dst.SetUint(i) return nil } return ErrNotSupported(src.Type(), dst.Type()) default: return ErrNotSupported(src.Type(), dst.Type()) } return nil } func (c *copier) setFloat(dst, src reflect.Value) error { switch src.Kind() { case reflect.Float32, reflect.Float64: dst.SetFloat(src.Float()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.SetFloat(float64(src.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.SetFloat(float64(src.Uint())) case reflect.String: if f, err := strconv.ParseFloat(src.String(), 64); err == nil { dst.SetFloat(f) return nil } return ErrNotSupported(src.Type(), dst.Type()) default: return ErrNotSupported(src.Type(), dst.Type()) } return nil } func (c *copier) setBool(dst, src reflect.Value) error { switch src.Kind() { case reflect.Bool: dst.SetBool(src.Bool()) case reflect.String: if b, err := strconv.ParseBool(src.String()); err == nil { dst.SetBool(b) return nil } // 尝试常见布尔表示 val := strings.ToLower(src.String()) if val == "true" || val == "yes" || val == "1" || val == "on" { dst.SetBool(true) return nil } if val == "false" || val == "no" || val == "0" || val == "off" { dst.SetBool(false) return nil } return ErrNotSupported(src.Type(), dst.Type()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.SetBool(src.Int() != 0) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.SetBool(src.Uint() != 0) default: return ErrNotSupported(src.Type(), dst.Type()) } return nil } func (c *copier) ignore(field reflect.Value, srcName, dstName string, tag *tagOption) bool { // 忽略空值 if tag != nil && tag.Contains(tagIgnore) { return true } // 忽略空值 if c.opt.ignoreEmpty && field.IsZero() { return true } // 忽略指定字段 if c.opt.skipFields != nil { if slices.Contains(c.opt.skipFields, srcName) || slices.Contains(c.opt.skipFields, dstName) { return true } } return false } func (c *copier) copyTime(dst, src reflect.Value) error { srcTime, dstTime := getTimeValueExt(src), getTimeValueExt(dst) // 双方都是时间类型,直接赋值(需要处理自定义类型转换) if srcTime.IsValid() && dstTime.IsValid() { dstTime.Set(srcTime) return nil } // 源是时间,目标是其他类型(包括 nil 指针) if srcTime.IsValid() { srcTimeValue := srcTime.Interface() if t, ok := srcTimeValue.(time.Time); ok { return c.timeToOther(dst, t) } if t, ok := srcTimeValue.(*time.Time); ok && t != nil { return c.timeToOther(dst, *t) } } // 目标是时间(可能是 nil 指针),源是其他类型 if dstTime.IsValid() || isTimeType(dst.Type()) { // 如果 dst 是 nil 指针,先创建实例 if dst.Kind() == reflect.Pointer && dst.IsNil() && dst.CanSet() { dst.Set(reflect.New(dst.Type().Elem())) dstTime = getTimeValueExt(dst) } if dstTime.IsValid() { return c.otherToTime(dstTime, src) } } return ErrNotSupported(src.Type(), dst.Type()) } func (c *copier) timeToOther(dst reflect.Value, src time.Time) error { switch dst.Kind() { case reflect.String: format := c.getTimeFormat(dst.Type()) dst.SetString(src.Format(format)) return nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.SetInt(src.Unix()) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.SetUint(uint64(src.Unix())) return nil case reflect.Float32, reflect.Float64: dst.SetFloat(float64(src.Unix()) + float64(src.Nanosecond())/1e9) return nil case reflect.Struct: if dst.Type() == reflect.TypeOf(time.Time{}) { dst.Set(reflect.ValueOf(src)) return nil } } return ErrNotSupported(reflect.TypeOf(src), dst.Type()) } func (c *copier) otherToTime(dst reflect.Value, src reflect.Value) error { src = indirect(src) switch src.Kind() { case reflect.String: return c.stringToTime(dst, src.String()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: dst.Set(reflect.ValueOf(time.Unix(src.Int(), 0))) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: dst.Set(reflect.ValueOf(time.Unix(int64(src.Uint()), 0))) return nil case reflect.Float32, reflect.Float64: sec := src.Float() nsec := int64((sec - float64(int64(sec))) * 1e9) dst.Set(reflect.ValueOf(time.Unix(int64(sec), nsec))) return nil case reflect.Struct: if src.Type() == reflect.TypeOf(time.Time{}) { dst.Set(src) return nil } case reflect.Map: // 支持从map构造时间,如:map[string]int{"year": 2023, "month": 1, "day": 1} return c.mapToTime(dst, src) } return ErrNotSupported(src.Type(), dst.Type()) } func (c *copier) getTimeFormat(dstType reflect.Type) string { if format, ok := c.opt.timeFormats[dstType]; ok { return format } if dstType.Kind() == reflect.String { if format, ok := c.opt.timeFormats[reflect.TypeOf("")]; ok { return format } } if format, ok := c.opt.timeFormats[reflect.TypeOf(nil)]; ok { return format } return time.RFC3339 } func (c *copier) stringToTime(dst reflect.Value, timeStr string) error { // 首先尝试数字字符串(时间戳) if sec, err := strconv.ParseInt(timeStr, 10, 64); err == nil { dst.Set(reflect.ValueOf(time.Unix(sec, 0))) return nil } // 尝试浮点数时间戳 if sec, err := strconv.ParseFloat(timeStr, 64); err == nil { nsec := int64((sec - float64(int64(sec))) * 1e9) dst.Set(reflect.ValueOf(time.Unix(int64(sec), nsec))) return nil } // 尝试各种时间格式 formats := c.getTimeFormats(dst.Type()) for _, format := range formats { if t, err := time.Parse(format, timeStr); err == nil { c.setTimeValue(dst, t) return nil } } return fmt.Errorf("cannot parse time string: %s", timeStr) } func (c *copier) setTimeValue(dst reflect.Value, t time.Time) error { if !dst.CanSet() { return ErrInvalidCopyDestination } // 处理指针类型 if dst.Kind() == reflect.Pointer { if dst.IsNil() { if !dst.CanSet() { return ErrInvalidCopyDestination } dst.Set(reflect.New(dst.Type().Elem())) } dst = dst.Elem() } // 目标类型是标准 time.Time if dst.Type() == reflect.TypeOf(time.Time{}) { dst.Set(reflect.ValueOf(t)) return nil } if setter, ok := dst.Addr().Interface().(interface{ SetTime(time.Time) }); ok { setter.SetTime(t) return nil } return ErrNotSupported(reflect.TypeOf(t), dst.Type()) } func (c *copier) getTimeFormats(dstType reflect.Type) []string { var formats []string // 添加特定类型的格式 if format, ok := c.opt.timeFormats[dstType]; ok { formats = append(formats, format) } // 添加字符串类型的格式(如果目标类型是字符串) if dstType.Kind() == reflect.String { if format, ok := c.opt.timeFormats[reflect.TypeOf("")]; ok { formats = append(formats, format) } } // 添加默认格式 if format, ok := c.opt.timeFormats[reflect.TypeOf(nil)]; ok { formats = append(formats, format) } // 添加内置的常见格式 builtinFormats := []string{ time.RFC3339, time.RFC3339Nano, "2006-01-02 15:04:05", "2006-01-02", "15:04:05", time.RFC1123, time.RFC822, time.ANSIC, "2006/01/02", "2006/01/02 15:04:05", "02 Jan 2006", "02 Jan 2006 15:04:05", } formats = append(formats, builtinFormats...) return formats } func (c *copier) mapToTime(dst reflect.Value, src reflect.Value) error { if src.Type().Key().Kind() != reflect.String { return ErrNotSupported(src.Type(), dst.Type()) } if src.Len() == 0 { return nil } // 从map中提取时间组件 year, month, day, hour, min, sec, nsec := 0, 1, 1, 0, 0, 0, 0 loc := time.UTC iter := src.MapRange() for iter.Next() { key := iter.Key().String() value := iter.Value() switch key { case "year", "Year": year = int(getIntValue(value)) case "month", "Month": month = int(getIntValue(value)) case "day", "Day": day = int(getIntValue(value)) case "hour", "Hour": hour = int(getIntValue(value)) case "minute", "Minute", "min", "Min": min = int(getIntValue(value)) case "second", "Second", "sec", "Sec": sec = int(getIntValue(value)) case "nanosecond", "Nanosecond", "nsec", "Nsec": nsec = int(getIntValue(value)) case "location", "Location", "loc", "Loc": if locStr, ok := value.Interface().(string); ok { if location, err := time.LoadLocation(locStr); err == nil { loc = location } } } } if year == 0 { year = time.Now().Year() } t := time.Date(year, time.Month(month), day, hour, min, sec, nsec, loc) return c.setTimeValue(dst, t) } func getIntValue(v reflect.Value) int64 { v = indirect(v) switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return int64(v.Uint()) case reflect.Float32, reflect.Float64: return int64(v.Float()) case reflect.String: if i, err := strconv.ParseInt(v.String(), 10, 64); err == nil { return i } } return 0 } func isTimeType(t reflect.Type) bool { if t == nil { return false } // 处理指针类型 for t.Kind() == reflect.Pointer { t = t.Elem() } // 直接比较标准 time.Time 类型 if t == reflect.TypeOf(time.Time{}) { return true } if _, ok := t.MethodByName("Time"); ok { return true } return false } func getTimeValue(v reflect.Value) reflect.Value { if !v.IsValid() { return reflect.Value{} } // 标准 time.Time 类型 if v.Type() == reflect.TypeOf(time.Time{}) { return v } // 检查是否为时间类型 if isTimeType(v.Type()) { return v } // 指针类型处理 if v.Kind() == reflect.Pointer && !v.IsNil() { elem := v.Elem() if isTimeType(elem.Type()) { return elem } } return reflect.Value{} } func getTimeValueExt(v reflect.Value) reflect.Value { standardTime := getTimeValue(v) if standardTime.IsValid() { return standardTime } // 如果无法直接识别,尝试转换 if v.IsValid() && v.CanInterface() { // 尝试通过接口转换 if converter, ok := v.Interface().(interface{ ToTime() time.Time }); ok { return reflect.ValueOf(converter.ToTime()) } // 尝试直接转换 if v.Type().ConvertibleTo(reflect.TypeOf(time.Time{})) { return v.Convert(reflect.TypeOf(time.Time{})) } } return reflect.Value{} }