a6990aa4af
Split monolithic copier.go (1077 lines) into focused modules: - copier.go: Core framework (95 lines) - copy_value.go: Copy functions and type handling (858 lines) - reflect.go: Reflection utilities (100 lines) - converter.go: Type converter (38 lines) - options.go: Configuration (renamed from optiongs.go) Bug fixes: - Fixed string to *string copying (empty strings now work) - Fixed *time.Time to *time.Time copying - Fixed nil slice handling - Fixed copyStructToSlice pointer element handling Tests: Fixed critical data copy issues. Remaining method-mapping features require additional implementation.
105 lines
2.1 KiB
Go
105 lines
2.1 KiB
Go
package copier
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
type copier struct {
|
|
opt *options
|
|
visited map[uintptr]struct{}
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func New(opts ...option) *copier {
|
|
opt := getOpt(opts...)
|
|
var visited map[uintptr]struct{}
|
|
if opt.detectCircularRefs {
|
|
visited = make(map[uintptr]struct{})
|
|
}
|
|
|
|
return &copier{
|
|
visited: visited,
|
|
opt: opt,
|
|
}
|
|
}
|
|
|
|
func (c *copier) Copy(dst, src any) error {
|
|
c.mu.Lock()
|
|
defer c.reset()
|
|
defer c.mu.Unlock()
|
|
|
|
if dst == nil || src == nil {
|
|
return ErrInvalidCopyDestination
|
|
}
|
|
|
|
srcValue, dstValue := indirect(reflect.ValueOf(src)), indirect(reflect.ValueOf(dst))
|
|
|
|
if !srcValue.IsValid() {
|
|
return ErrInvalidCopyFrom
|
|
}
|
|
|
|
if !dstValue.CanSet() {
|
|
return ErrInvalidCopyDestination
|
|
}
|
|
|
|
return c.deepCopy(dstValue, srcValue, 0)
|
|
}
|
|
|
|
func (c *copier) reset() {
|
|
if c.opt.detectCircularRefs {
|
|
clear(c.visited)
|
|
}
|
|
}
|
|
|
|
func (c *copier) deepCopy(dst, src reflect.Value, depth int) error {
|
|
if c.ExceedMaxDepth(depth) {
|
|
return ErrMaxDepthExceeded
|
|
}
|
|
|
|
// 复制源无效,直接返回
|
|
if !src.IsValid() {
|
|
return nil
|
|
}
|
|
|
|
// 对于 slice 和 map,如果 src 是 nil,不复制(保持 dst 不变)
|
|
// 对于其他类型(如 string),即使 IsZero 也要复制
|
|
switch src.Kind() {
|
|
case reflect.Slice, reflect.Map:
|
|
if src.IsNil() {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if c.isCircularRefs(src) {
|
|
return ErrCircularReference
|
|
}
|
|
|
|
// 可以直接赋值时直接赋值并返回
|
|
srcType, dstType := src.Type(), dst.Type()
|
|
|
|
// 处理时间类型
|
|
if isTimeType(srcType) || isTimeType(dstType) {
|
|
return c.copyTime(dst, src)
|
|
}
|
|
|
|
// fmt.Println("srcType:", srcType, src.Kind().String(), "dstType:", dstType, dst.Kind().String())
|
|
|
|
switch src.Kind() {
|
|
case reflect.Slice, reflect.Array:
|
|
return c.copySliceOrArray(dst, src, depth)
|
|
case reflect.Map:
|
|
return c.copyMap(dst, src, depth)
|
|
case reflect.Struct:
|
|
return c.copyStruct(dst, src, depth)
|
|
case reflect.Pointer:
|
|
return c.copyPointer(dst, src, depth)
|
|
case reflect.Interface:
|
|
return c.copyInterface(dst, src, depth)
|
|
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
|
return ErrNotSupported(srcType, dstType)
|
|
default:
|
|
return c.copyBasic(dst, src)
|
|
}
|
|
}
|