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