不安全,但不会崩溃;copy 按从左到右顺序复制,当 dst 起始地址 > src 起始地址时(如 copy(s[i:], s), i > 0),src 数据会被提前覆盖,导致错误结果。

copy 函数对重叠 slice 的行为是否安全?
不安全,但不是崩溃或未定义行为——copy 会按「从左到右」顺序逐元素复制,因此当目标 dst 和源 src 重叠且 dst 起始位置在 src 起始位置之后时,会出现数据被提前覆盖的问题。
什么情况下重叠复制会出错?
典型错误场景是用 copy 实现「向左平移」或「删除开头元素」这类操作,例如:
data := []int{1, 2, 3, 4, 5}
copy(data[0:], data[1:]) // 想变成 [2,3,4,5,5],实际得到 [2,3,4,5,5] —— 这次碰巧对了但换成:
data := []int{1, 2, 3, 4, 5}
copy(data[1:], data[0:]) // 想把前面的往右挪一位,结果是 [1,1,1,1,1]原因:第 0 个元素先拷进 data[1],接着第 1 个元素(已被改过的 data[1])再拷进 data[2],以此类推。
-
dst起始地址 >src起始地址 → 可能出错(如copy(s[i:], s),i > 0) -
dst起始地址 src 起始地址 → 安全(如copy(s, s[i:])) - 底层指向同一底层数组、且有交集,才叫重叠;若无交集(如不同 make 出的 slice),则无影响
需要重叠复制时该用什么?
Go 标准库不提供「安全重叠复制」的内置函数,必须手动控制方向:
- 想「向前覆盖」(dst 偏移更大)→ 改用 反向循环:
for i := len(src) - 1; i >= 0; i-- { dst[i+offset] = src[i] } - 标准做法是避免依赖
copy处理重叠:用append构造新 slice,或用copy+ 显式切片组合(如copy(dst, src[n:])) - 如果只是删头/尾,直接用切片表达式更清晰:
s = s[1:]或s = s[:len(s)-1],不涉及copy
为什么 runtime.copy 不做重叠检测?
性能优先。Go 的 copy 对应底层 memmove(而非 memcpy),本可安全处理重叠——但 Go 选择让 copy 语义等价于「从低地址到高地址顺序赋值」,以便编译器优化和预测行为。
这意味着:
- 即使底层用了
memmove,Go 规范仍要求copy表现为左到右复制 - 不能依赖运行时自动修正;写重叠逻辑前,必须自己判断方向并选对策略
- 静态分析工具(如
staticcheck)可能报SA4001警告:「copy of overlapping slices」
重叠本身不 panic,但结果取决于你有没有意识到复制方向这回事。漏掉这点,bug 往往只在特定长度或偏移下暴露。


















