go中將切片當作函數參數傳入,切片的變化


記錄一下slice的擴容問題和將slice作為函數參數的問題

sliceappend操作有可能會觸發擴容,這個主要看slice的擴容算法

假設我們又一個slice,那么他的結構體大概意思應該是如下:

type slice struct{
    value *int //這是指向底層數組的指針
    length uint //長度
    capacity uint //容量
}

當我們將一個切片作為函數參數傳遞給函數的時候,其實采用的是值傳遞,因此我們傳遞給函數的參數其實是上面這個結構體的值拷貝。

但是呢,因為value是一個指向數組的指針,所以我們對這個指針進行值拷貝的時候,得到的指針還是指向了同一個底層數組。因此我們可以拷貝來的指針對底層數組的值進行修改,從而修改了切片的值。

但是!!!!

我們以值傳遞的方式傳遞上面的結構體的時候,同時也是傳遞了lengthcapacity的值拷貝,因為這兩個成員並不是指針,因此,當我們從函數返回的時候,外層切片結構體的lengthcapacity這兩個成員並沒有改變。

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

另外,千萬不要在牛客網的代碼中使用全局變量,否則不同的測試用例會相互影響。。。。太慘烈了。。。。血的教訓。。。。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM