在函数内部能修改入参slice吗?不一定

65 阅读2分钟

写在前面

本文主要是考察对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