go slice在函数间的传递模式
在 Go 语言中,slice 是值传递(所有类型都是值传递),但修改 slice 的元素可以影响到外部。
详细解释
1. 值传递的本质
当你传递 slice 给函数时,传递的是 slice 头的副本。slice 头包含三个字段:
- 指向底层数组的指针
- 长度(len)
- 容量(cap)
typesliceHeaderstruct{Datauintptr// 指向底层数组的指针LenintCapint}2. 修改元素 -可以影响外部
funcmodifyElement(s[]int){s[0]=100// 修改底层数组的元素}funcmain(){nums:=[]int{1,2,3}modifyElement(nums)fmt.Println(nums)// [100 2 3] ✅ 外部被影响}原因:副本中的Data指针指向同一个底层数组。
3. 修改长度/容量 -不能影响外部
funcmodifyLen(s[]int){s=append(s,4)// 可能改变 len 和 cap,甚至指向新数组s[0]=100}funcmain(){nums:=[]int{1,2,3}modifyLen(nums)fmt.Println(nums)// [1 2 3] ❌ 外部不受影响}4. 使用指针才能完全修改
funcmodifySlice(s*[]int){*s=append(*s,4)// 修改原 slice(*s)[0]=100}funcmain(){nums:=[]int{1,2,3}modifySlice(&nums)fmt.Println(nums)// [100 2 3 4] ✅ 完全受控}总结
- 修改元素:✅ 影响外部(共享底层数组)
- 修改长度/容量:❌ 不影响外部(副本的 len/cap 独立)
- 重新赋值整个 slice:❌ 不影响外部(副本的 Data 指针改变)
- 需要完全修改时:使用指针
*[]T或返回新 slice
这种设计兼顾了性能和安全性,是最常见的 Go 语言实践。
