
Go 的 slice 是引用类型,append 操作中若重复复用同一底层数组的 slice 变量,会导致所有元素指向相同内存地址,从而产生意外的覆盖行为。
go 的 slice 是引用类型,`append` 操作中若重复复用同一底层数组的 slice 变量,会导致所有元素指向相同内存地址,从而产生意外的覆盖行为。
在 Go 中,slice 并非传统意义上的“值类型”,而是一个三元结构体:包含指向底层数组的指针、长度(len)和容量(cap)。这意味着当你执行 append(slice2, slice) 时,实际追加的是对 slice 当前底层数据的引用,而非其内容的深拷贝。
回到原始代码:
slice := []int{0, 0}
slice2 := [][]int{}
for i := range slice {
slice[0] = i
slice[1] = i
slice2 = append(slice2, slice) // ⚠️ 追加的是同一个 slice 头部(含相同指针)
}
fmt.Println(slice2) // 输出 [[1 1] [1 1]]该循环共执行两次(i = 0 和 i = 1),但 slice 始终是同一个变量,其底层数组未变。第一次迭代后,slice = [0 0] 被追加进 slice2 —— 此时 slice2[0] 指向该数组;第二次迭代中,slice 被修改为 [1 1],并再次追加:slice2[1] 指向同一底层数组。最终 slice2[0] 和 slice2[1] 实际共享内存,打印时均显示 [1 1]。
✅ 正确做法是:每次迭代创建独立的 slice 值,确保底层数组隔离:
func main() {
slice2 := [][]int{}
for i := range [2]int{} { // 等价于 range []int{0,0},但更清晰表达迭代次数
ns := []int{i, i} // 每次新建 slice → 新底层数组
slice2 = append(slice2, ns)
}
fmt.Println(slice2) // 输出 [[0 0] [1 1]]
}? 关键要点:
- Go 中没有隐式深拷贝;
append不复制底层数组,只复制 slice header。 - 若需保留某次状态,必须显式创建新 slice(如
append([]int{}, slice...)或字面量初始化)。 - 使用
append(dst, src...)实现浅拷贝:newSlice := append([]int{}, slice...)。
总结:理解 slice 的引用本质是避免此类“幽灵覆盖”问题的核心。永远记住——你操作的不是数据本身,而是指向它的描述符。

















