当 slice 作为函数参数时,就是一个普通的结构体。
- 直接传 slice,在调用者看来,实参 slice 并不会被函数中的操作改变。
- 传的是 slice 的指针,在调用者看来,是会被改变原 slice 的。
值得注意的是,不管传的是 slice 还是 slice 指针,如果改变了 slice 底层数组的数据,会反应到实参 slice 的底层数据。
底层数据在 slice 结构体里是一个指针,尽管 slice 结构体自身不会被改变,也就是说底层数据地址不会被改变。 但是通过指向底层数据的指针,可以改变切片的底层数据。
func TestSlice(t *testing.T) {
arr := []int{1, 2, 3, 4, 5}
fmt.Printf("%p %v \n", arr, arr)
testSlice(arr)
fmt.Printf("%p %v \n", arr, arr)
testSlicePtr(&arr)
fmt.Printf("%p %v \n", arr, arr)
}
func testSlice(s []int) {
s = append(s, 100)
fmt.Printf("%p %v\n", s, s)
}
func testSlicePtr(s *[]int) {
*s = append(*s, 0)
fmt.Printf("%p %v\n", *s, *s)
}
0xc0000124b0 [1 2 3 4 5]
// 直接传slice,传的是值
// 里面append之后扩容了,赋值了一个新的数组,不会改变到外面的slice
0xc000016230 [1 2 3 4 5 100]
0xc0000124b0 [1 2 3 4 5]
0xc000016280 [1 2 3 4 5 0]
0xc000016280 [1 2 3 4 5 0]
本质上还是因为 go 是值传递。