有时候我们会将slice当做参数传递到函数,给这个slice做一些修改的情况。想到slice是引用传递,可以直接传递slice用作修改,于是可能出现下面这种情况:
1 | package main |
我们利用modifySlice函数对传入的arr进行修改和添加的操作,想到slice是引用传递,在modifySlice中的修改必然会生效。
但是实际上呢,我们看一下运行情况:
1 | # go run main |
运行结果表明我们对s[0]做的修改没有生效,添加新元素的操作也未生效,这是为什么呢?
原因就在于添加新元素是用的append,并将原先的引用重新赋值了!
我们把引用当成指针来看,指针指向的内容就是slice的数据内容。
指针本身是一种变量类型,指针类型在传递时,是值传递!
也就是说我们在外面调用modifySlice时,传入arr是一个指针变量,当进入到modifySlice函数时,形参arr跟外面传入的arr并不是一个值,是arr的值拷贝!但是他们的值是一样的,即指向的数据内容都是slice中的数据。
然而我们用这种方式:arr = append(arr, 2),这是在修改指针,并不是在修改指针指向的数据!
append可能会因为arr的cap不足,重新分配空间(扩容过的数组),所以append有一个返回参数。
如果append超过设定的区间,那么Slice底层就会扩容了
我们对modifySlice中的arr进行了修改,但是arr是指针,仅仅是外层传入的slice指针的拷贝,说明我们并没有对外层的slice重新赋值!
这就是添加新元素失败的原因。
我们再执行arr[0] = 0,实际上是修改的是指针指向的数据的内容(扩容过的数组)!这里肯定不会生效!
如果把函数modifySlice中的语句调换下顺序,修改为:
1 | func modifySlice(arr []int) { |
则运行情况则会改变:
1 | # go run main |
这里用arr[0] = 0做了修改,实际上是修改指针指向的数据的内容(未扩容的数组)!这里就会修改到外部传入的arr。
以上。