Golang中操作赋值得到的slice为何会修改原切片的底层数据?
Go切片操作修改原切片的底层逻辑解释
核心前提:Go切片的底层结构
- Go的切片本质是一个三元结构体,包含三个字段:
- 指向底层数组的指针
*T - 切片当前长度
len - 切片最大容量
cap
- 指向底层数组的指针
- 我们平时对切片的赋值操作(比如
b := a),只是拷贝这个切片结构体本身,不会拷贝底层数组,所以赋值后a和b指向同一块底层数组内存。
代码逐行拆解
先列出示例代码方便对照:
func main() { a := []int{1,2,3,4} b := a b = append(b[0:1], b[2:]...) fmt.Println(b) fmt.Println(a) }
- 初始化
a := []int{1,2,3,4}:a的len=4,cap=4,底层数组为[1,2,3,4] b := a:拷贝切片结构体给b,此时b的len=4、cap=4,和a指向同一个底层数组- 执行
append(b[0:1], b[2:]...):- 首先
b[0:1]是切片截取操作,未指定第三个容量参数时,新切片的容量=原切片容量-起始索引,所以b[0:1]的len=1,cap=4,底层数组还是原来的那块 - 此时append需要追加2个元素(
b[2:]是[3,4]),1+2=3 ≤ cap=4,不会触发扩容,直接在原底层数组上修改:从索引1的位置开始写入3、4 - 原底层数组会从
[1,2,3,4]被修改为[1,3,4,4](索引3的4没有被覆盖) - append返回的新切片赋值给b,此时b的len更新为3,cap还是4
- 首先
- 打印结果:
- b的len是3,所以输出
[1,3,4] - a的结构体没有被修改,len还是4,会读取底层数组全部4个元素,所以输出
[1,3,4,4]
- b的len是3,所以输出
误区说明
你以为b := a是值传递就不会影响原切片的认知是对的,切片赋值确实是值传递,但传递的是切片结构体本身,结构体里的指针还是指向同一块底层数组,只要append没有触发扩容,对底层数组的写入就会同步反映到所有指向该数组的切片上。如果append时需要的总长度超过切片容量,Go会新分配一块更大的底层数组,把旧数据拷贝过去,此时修改才不会影响原来的切片。
内容的提问来源于stack exchange,提问作者Say.My.Name.
相关产品推荐
相关产品推荐

