有时候我们会将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
。
以上。