iMIKU.moe
447 字
2 分钟
Deep Copy

Deep Copy#

为解决循环指针而设计的深度拷贝,目前 chan/map/func 还没有实现。

源码#

package main

import (
	"reflect"
)

func DeepCopy[T any](src, dst *T) {
	srv := reflect.ValueOf(src)
	srv = srv.Elem()
	drv := reflect.ValueOf(dst)
	drv = drv.Elem()
	addrMap := map[uint64]reflect.Value{}
	handleStruct(srv, drv, addrMap)
}

func genKey(src reflect.Value) uint64 {
	switch src.Kind() {
	case reflect.Pointer, reflect.Chan, reflect.Map, reflect.UnsafePointer, reflect.Func, reflect.Slice:
		return uint64(src.Pointer())<<6 + uint64(src.Kind())<<1
	default:
		return uint64(src.UnsafeAddr())<<6 + uint64(src.Kind())<<1 + 1
	}
}

func handlePointer(src, dst reflect.Value, addrMap map[uint64]reflect.Value) {
	src = src.Elem()
	addr := genKey(src)
	ndst, ok := addrMap[addr]
	if !ok {
		ndst = reflect.New(src.Type()).Elem()
		addrMap[addr] = ndst
		switch src.Kind() {
		case reflect.Struct:
			handleStruct(src, ndst, addrMap)
		case reflect.Interface:
			handleInterface(src, ndst, addrMap)
		case reflect.Pointer:
			handlePointer(src, ndst, addrMap)
		case reflect.Array:
			handleArray(src, ndst, addrMap)
		case reflect.Slice:
			handleSlice(src, ndst, addrMap)
		case reflect.Chan:
		case reflect.Func:
		case reflect.Map:
		default:
			ndst.Set(src)
		}
	}
	dst.Set(ndst.Addr())
}

func handleStruct(src, dst reflect.Value, addrMap map[uint64]reflect.Value) {
	addrMap[genKey(src)] = dst
	for i := 0; i < src.NumField(); i++ {
		srcf := src.Field(i)
		addr := genKey(srcf)
		dstf, ok := addrMap[addr]
		if !ok {
			ndstf := dst.Field(i)
			addrMap[addr] = ndstf
			switch srcf.Kind() {
			case reflect.Struct:
				handleStruct(srcf, ndstf, addrMap)
			case reflect.Interface:
				handleInterface(srcf, ndstf, addrMap)
			case reflect.Pointer:
				handlePointer(srcf, ndstf, addrMap)
			case reflect.Array:
				handleArray(srcf, ndstf, addrMap)
			case reflect.Slice:
				handleSlice(srcf, ndstf, addrMap)
			case reflect.Chan:
			case reflect.Func:
			case reflect.Map:
			default:
				ndstf.Set(srcf)
			}
		} else {
			dst.Field(i).Set(dstf)
		}
	}
}

func handleInterface(src, dst reflect.Value, addrMap map[uint64]reflect.Value) {
	src = src.Elem()
	switch src.Kind() {
	case reflect.Struct:
		handleStruct(src, dst, addrMap)
	case reflect.Interface:
		handleInterface(src, dst, addrMap)
	case reflect.Pointer:
		handlePointer(src, dst, addrMap)
	case reflect.Array:
		handleArray(src, dst, addrMap)
	case reflect.Slice:
		handleSlice(src, dst, addrMap)
	case reflect.Chan:
	case reflect.Func:
	case reflect.Map:
	default:
		dst.Set(src)
	}
}

func handleArray(src, dst reflect.Value, addrMap map[uint64]reflect.Value) {
	for i := 0; i < src.Len(); i++ {
		srcf := src.Index(i)
		addr := genKey(srcf)
		dstf, ok := addrMap[addr]
		if !ok {
			ndstf := dst.Index(i)
			addrMap[addr] = ndstf
			switch srcf.Kind() {
			case reflect.Struct:
				handleStruct(srcf, ndstf, addrMap)
			case reflect.Interface:
				handleInterface(srcf, ndstf, addrMap)
			case reflect.Pointer:
				handlePointer(srcf, ndstf, addrMap)
			case reflect.Array:
				handleArray(srcf, ndstf, addrMap)
			case reflect.Slice:
				handleSlice(srcf, ndstf, addrMap)
			case reflect.Chan:
			case reflect.Func:
			case reflect.Map:
			default:
				ndstf.Set(srcf)
			}
		} else {
			dst.Index(i).Set(dstf)
		}
	}
}

func handleSlice(src, dst reflect.Value, addrMap map[uint64]reflect.Value) {
	addrMap[genKey(src)] = dst
	dst.Grow(src.Len() - dst.Len())
	dst.SetLen(src.Len())
	for i := 0; i < src.Len(); i++ {
		srcf := src.Index(i)
		addr := genKey(srcf)
		dstf, ok := addrMap[addr]
		if !ok {
			ndstf := dst.Index(i)
			addrMap[addr] = ndstf
			switch srcf.Kind() {
			case reflect.Struct:
				handleStruct(srcf, ndstf, addrMap)
			case reflect.Interface:
				handleInterface(srcf, ndstf, addrMap)
			case reflect.Pointer:
				handlePointer(srcf, ndstf, addrMap)
			case reflect.Array:
				handleArray(srcf, ndstf, addrMap)
			case reflect.Slice:
				handleSlice(srcf, ndstf, addrMap)
			case reflect.Chan:
			case reflect.Func:
			case reflect.Map:
			default:
				ndstf.Set(srcf)
			}
		} else {
			dst.Index(i).Set(dstf)
		}
	}
}
Deep Copy
https://blog.imiku.moe/posts/deep_copy/
作者
delichik
发布于
2024-06-24
许可协议
CC BY-NC-SA 4.0