Go标准库无reflect.DeepCopy,需手动实现:检查nil指针与可寻址性,用map[uintptr]bool检测循环引用,避免json方案的语义丢失与性能问题。

reflect.DeepCopy 不存在,别被名字骗了
Go 标准库根本没有 reflect.DeepCopy 这个函数。所有声称“用 reflect 包一行实现深拷贝”的代码,其实都是自己写的递归逻辑——而这个递归过程就是性能瓶颈的根源。它不是慢在“反射调用”,而是每次 reflect.New、reflect.MakeSlice、reflect.MakeMap 都触发堆分配,且字段遍历、类型检查、字符串比较(字段名)、接口断言全在运行时发生。中等嵌套结构体一次拷贝,比手写 Clone() 慢 5–20 倍,不是错觉。
手动 Clone() 方法:快,但得你写
这是最可控、零反射开销的方式,适合字段稳定、嵌套不深的结构体。关键不是“全量复制”,而是**只深拷贝真正需要隔离的引用字段**:
-
[]T:用make([]T, len(src))+copy(dst, src);若T含指针或 map,需对每个dst[i]单独递归处理 -
map[K]V:先make(map[K]V),再for k, v := range src { dst[k] = deepCopy(v) } -
*T:判空后if src != nil { dst = &(*src).Clone() }(假设T也实现了Clone()) - 未导出字段、
func、chan、unsafe.Pointer自动跳过,不 panic,语义清晰
第三方库如 ulule/deepcopier:编译期生成,运行时零反射
它不靠运行时反射遍历,而是用代码生成器(deepcopier generate)在编译前为每个目标 struct 生成专用的 CopyTo() 函数。结果是:和手写 Clone() 性能几乎一致,但省去了重复劳动。它还能处理字段映射、忽略字段、条件复制,且天然跳过未导出字段和不可复制类型(如 sync.Mutex)。唯一代价是构建流程多一步,以及不能动态处理未知类型。
序列化兜底:gob 最靠谱,JSON 有坑
当结构体字段动态变化、或你完全不想管内存模型时,encoding/gob 是最接近“语义正确”的通用方案:它原生支持指针、slice、map、interface{},且不依赖字段名字符串(比 JSON 更稳定)。但注意:gob 要求类型在 encode/decode 两端完全一致(包括包路径),且无法处理 func、unsafe.Pointer 和含非导出字段的私有状态。JSON 则更脆弱:会丢掉 nil slice/map、把 time.Time 变字符串、无法还原未导出字段——仅适合纯数据 DTO 场景。
立即学习“go语言免费学习笔记(深入)”;
真正容易被忽略的点是:深拷贝从来不是“越通用越好”。90% 的误用,源于没想清楚——那个字段到底需不需要独立?改它会不会影响其他协程?要不要保留原始对象的 sync.Mutex 状态?盲目上反射或 gob,反而掩盖了设计问题。



















