记录一下slice
的扩容问题和将slice
作为函数参数的问题
slice
的append
操作有可能会触发扩容,这个主要看slice
的扩容算法
假设我们又一个slice
,那么他的结构体大概意思应该是如下:
type slice struct{
value *int //这是指向底层数组的指针
length uint //长度
capacity uint //容量
}
当我们将一个切片作为函数参数传递给函数的时候,其实采用的是值传递,因此我们传递给函数的参数其实是上面这个结构体的值拷贝。
但是呢,因为value
是一个指向数组的指针,所以我们对这个指针进行值拷贝的时候,得到的指针还是指向了同一个底层数组。因此我们可以拷贝来的指针对底层数组的值进行修改,从而修改了切片的值。
但是!!!!
我们以值传递的方式传递上面的结构体的时候,同时也是传递了length
和capacity
的值拷贝,因为这两个成员并不是指针,因此,当我们从函数返回的时候,外层切片结构体的length
和capacity
这两个成员并没有改变。
所以我们可以解释如下现象,就是当我们传递切片给函数的时候,并且在被调函数中通过append
操作向切片中增加了值,但是当函数返回的时候,我们看到的切片的值还是没有发生变化,其实底层数组的值是已经改变了的(如果没有触发扩容的话),但是由于长度length
没有发生改变,所以我们看到的切片的值也没有发生改变。
func main(){
a:=[]int{1,2,3} //长度为3,容量为3
b:=make([]int,1,8) //长度为1,容量为8
test(a,b)
}
func test(a,b []int){
// 触发了扩容,连底层数组的地址都发生了改变,但是因为是值传递,所以在main中的a还是指向原来的底层数组,长度容量不变还是为3
// test 函数中a触发了扩容,底层数组的地址和main种的a的底层数组不同了,长度为变为4,容量大于3了。
a=append(a,4)
// 没有触发扩容,所以test种的b和main中的b指向了同一个底层数组,但是在test中b的长度变为了2,容量不变,因为没有扩容。
// 因为是值传递,所以这个长度的变化并不能影响main中的b的切片结构体
// 因为实质上b从main进入test还是值传递,只不过值拷贝的是b的切片结构体
b=append(b,2)
}
但是,如果我们不通过append
改变切片的值,那么在被调函数中对切片的操作就能够影响主调函数中的切片,因为都是对同一个底层数组的操作,并且通过下标对切片进行操作的时候没有改变切片的长度,所以在主调函数中是能够访问到我们对切片的修改内容的