写在前面
本文主要是考察对slice的底层理解,知识点就是slice struct有一个dataPtr,是一个指向数组的指针。理解这一点就能理解本问题,但是这个地方极易容易出错。
举个例子
func testSlice1(arr []int) {
arr[0] = 3
arr[1] = 4
}
func testSlice2(arr []int) {
arr = append(arr, 5, 6, 7, 8, 9, 10)
arr[0] = 3
arr[1] = 4
}
func testSlice3(arr []int) {
arr[0] = 3
arr[1] = 4
arr = append(arr, 5, 6, 7, 8, 9, 10)
}
func main() {
arr1 := []int{1, 2}
testSlice1(arr1)
fmt.Println(arr1) // [3 4]
arr2 := []int{1, 2}
testSlice2(arr2)
fmt.Println(arr2) // [1 2]
arr3 := []int{1, 2}
testSlice3(arr3)
fmt.Println(arr3) // [3 4]
}
分析
testSlice1
修改了arr slice底层指向的数组,因此输出:[3,4],容易理解。testSlice2
先是像arr slice中增加6个元素,这个操作导致arr底层指向的数组发生了变化,但是arr作为参数传进来是值传递,因此这次扩容虽然修改了入参arr底层指向的数组,但是不影响main函数中的arr2,所以该函数后面修改arr[0],arr[1]并不会改变main的arr2,因此输出:[1,2]testSlice3
先修改了arr slice底层指向的数组元素,跟testSlice1
一样,会改变main函数中的arr3,后面向arr中追加6个元素,导致arr底层指向的数组发生了改变,因为arr是值传递,不会改变main的arr3,因此输出:[3,4]
总结
函数能否改变slice主要在修改slice的时候是否发生了扩容:
- 如果在修改slice的时候没有发生扩容则会改变入参
- 如果在修改slice的时候发生了扩容则不会改变入参
个人建议:不要修改slice的内容,仅仅做生成新slice用,如newSlice = oldSlice[i:j],如果要修改slice则建议先copy一份,修改copy后的slice