reflect.Copy不能用于深拷贝,因其仅支持同类型切片的元素级浅复制,不递归处理结构体、指针、map等;标准库无DeepCopy方法;深拷贝需手动递归实现或使用成熟第三方库。

为什么 reflect.Copy 不能直接用于深拷贝
reflect.Copy 只适用于切片([]T)之间的元素级复制,且要求源和目标类型完全一致、底层可寻址。它不递归处理结构体字段、指针、map 或嵌套 slice,更不会分配新内存——本质上只是 memmove 的反射封装。试图用它拷贝一个含指针字段的 struct,结果是浅拷贝,后续修改仍会相互影响。
用 reflect.Value.DeepCopy?不存在
Go 标准库中根本**没有** reflect.Value.DeepCopy 方法。这是常见误解,源于混淆了其他语言(如 Python 的 copy.deepcopy)或第三方库的 API。标准 reflect 包只提供类型检查、字段遍历、值读写等基础能力,深拷贝逻辑必须手动实现。
手写反射深拷贝的关键路径
核心思路:递归遍历值的类型与 Kind,对每种情况做对应处理——分配新内存、复制原始值、递归处理子项。需特别注意:
- 只处理可设置(
CanSet())且可寻址(CanAddr())的值;不可导出字段无法写入,跳过或报错 -
reflect.Ptr:新建指针,递归拷贝所指值,再用reflect.New+Elem().Set() -
reflect.Struct:遍历每个字段,对字段值递归调用拷贝函数 -
reflect.Map:用reflect.MakeMapWithSize创建新 map,遍历 key/value 分别拷贝后SetMapIndex -
reflect.Slice:用reflect.MakeSlice创建新 slice,逐元素拷贝并Index(i).Set() - 基础类型(
Int,String,Bool等):直接reflect.Copy或Set()
示例片段(简化版):
立即学习“go语言免费学习笔记(深入)”;
func deepCopy(v reflect.Value) reflect.Value {
if !v.IsValid() {
return v
}
if v.CanInterface() && v.Kind() == reflect.Ptr {
if v.IsNil() {
return reflect.Zero(v.Type())
}
nv := reflect.New(v.Elem().Type())
nv.Elem().Set(deepCopy(v.Elem()))
return nv
}
// ... 其他 kind 处理
}实际项目中更推荐用 github.com/jinzhu/copier 或 golang.org/x/exp/maps 吗?
不推荐盲目依赖 copier:它用反射+代码生成混合策略,但默认开启“忽略不可导出字段”和“跳过 nil 指针”,行为不易预测;某些嵌套 map/slice 场景会 panic。而 x/exp/maps 仅提供 map 工具函数,不解决深拷贝问题。
真正稳妥的做法是:
- 若对象结构固定,用
encoding/gob或json.Marshal/Unmarshal(注意 json 会丢掉私有字段、chan、func、不支持循环引用) - 若性能敏感且类型有限,为关键 struct 实现
Clone() *T方法,避免反射开销 - 必须用反射时,优先复用经生产验证的库如
github.com/mohae/deepcopy,它明确处理了 interface{}、unsafe.Pointer、自定义 Unmarshaler 等边界
最易被忽略的一点:反射深拷贝无法穿透 unsafe.Pointer 和 uintptr,这类值只能原样复制,可能引发悬垂指针——如果你的 struct 里混用了这些,反射方案本身就不适用。










