記錄一下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
改變切片的值,那么在被調函數中對切片的操作就能夠影響主調函數中的切片,因為都是對同一個底層數組的操作,並且通過下標對切片進行操作的時候沒有改變切片的長度,所以在主調函數中是能夠訪問到我們對切片的修改內容的