reflect.copy要求目标切片可寻址且类型严格匹配,仅浅拷贝、不处理嵌套引用,复制数取决于len(dst),非cap;错误用法如传字面量、丢失可寻址性或类型不兼容均导致panic。

reflect.Copy要求目标切片必须可寻址
传入 reflect.ValueOf(dst) 是常见错误——它返回的是不可寻址的副本,reflect.Copy 会直接 panic:"reflect: Copy using unaddressable value"。正确做法是先取地址再解引用:reflect.ValueOf(&dst).Elem(),或用 reflect.Value.Addr().Elem()(前提是 dst 本身可寻址)。
常见踩坑点:
- 对字面量切片调用:
reflect.Copy(reflect.ValueOf([]int{1,2}), ...)→ panic - 对函数参数中未取地址的切片变量使用 → panic
- 用
reflect.Value.Convert()或reflect.Value.Interface()中间转换后丢失可寻址性 → panic
源和目标切片类型必须严格一致
reflect.Copy 不做类型转换,只做值赋值,且要求元素类型满足 AssignableTo(不是 ConvertibleTo)。例如 []int 和 []int64、[]string 和 []interface{} 都会 panic:"reflect: Copy: type mismatch"。
典型误用场景:
- 想把
[]interface{}转成[]string→reflect.Copy完全不支持,必须手动遍历 + 类型断言 - 结构体切片中字段名相同但嵌套类型不同(如
A.Field是*T,B.Field是T)→ 即使字段名一样也会因元素类型不匹配而失败 - 使用
reflect.TypeOf(src).Kind() == reflect.Slice检查后就调用,却没验证src.Type().Elem()和dst.Type().Elem()是否 AssignableTo → 运行时 panic
复制数量由目标切片长度决定,不是容量
和内置 copy() 一样,reflect.Copy 实际复制个数是 min(len(src), len(dst)),只看 len,完全忽略 cap。如果目标切片是 make([]T, 0, 100),len(dst) 是 0,那 reflect.Copy 返回 0,什么都不会写入。
安全写法要点:
- 分配目标切片时必须用
make([]T, len(src)),不是make([]T, 0, len(src)) - 若目标切片已存在,需提前检查
reflect.Value.Len() >= srcLen,否则静默截断 - 永远检查返回值
n:若n != len(src),说明没复制全,应视为异常(尤其在配置复制等关键路径)
reflect.Copy不是深拷贝,也不处理指针/嵌套引用
reflect.Copy 的行为等价于循环调用 dst[i].Set(src[i]),仅逐元素浅层赋值。如果切片元素是结构体指针、含 map 字段的 struct、或嵌套 slice,复制后新旧切片仍共享底层数据。
这意味着:
-
[]*MyStruct复制后,两个切片里每个*MyStruct指向同一块内存 → 改一个,另一个也变 -
[]struct{ Data []int }复制后,Data字段的底层数组仍共享 → append 到任一Data都可能影响另一个 - 它不会递归进入 struct 字段、不会 deep copy map、不会处理 interface{} 内部值
真正需要隔离修改时,别碰 reflect.Copy —— 直接用 make + copy(基础类型),或上 github.com/mohae/deepcopy / copier.Copy(复杂嵌套),或者自己写递归反射逻辑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











