一、结论
Golang 参数传递,
全部是传值
。
二、为什么
- 对于map,slice这样的类型,作为参数传递,明明是传值,但是在函数中修改值后,在原函数仍然能访问到修改后的值。
- 如果你有C++基础,那么对于slice的理解,很容易就懂了,Slice的内部,就是这么个东东.
template<typename T>
class Slice {
public:
~Slice();
Slice(size_t len , size_t cap)
Slice(const Slice&v);
// 下面这三个成员,非常的重要
T* Data; //array of datas
size_t Len;
size_t Cap;
};
- 函数之间的传值,是浅拷贝
- 所以你在函数之间使用slice传值,是完全ok的,他们都共享Data指针(前提是append时,有足够的空间(cap),否则会生成新的slice,这个新的slice跟之前的,就没有一毛钱关系了)
三、代码说明
- 我们通过一段go代码来展示,结论是否与上面的分析一致,详细的讲解,都在注释里面了,看懂下面的代码,你会更加了解go这个神奇的语言了。
func exampleFunc(arr []int) {
arr[0] = 100
//由于没有超过cap,所以不会生成新的slice
arr = append(arr, 11111)
}
func main() {
//创建一个int slice
arr := make([]int, 2, 5)
//fill idx
for i := 0; i < len(arr); i++ {
arr[i] = i
}
//讲arr作为参数,传递到exampleFunc函数中
exampleFunc(arr)
for idx := range arr {
fmt.Printf("idx=%d,value=%d\n", idx, arr[idx])
}
//获取slice的data,可以看到,我们在modify中的修改,已经成功了
//但是由于exampleFunc函数的参数传的是arr的值,所以没法修改len和cap
//所以你不能够使用for range来进行迭代输出,因为for range只会在 [0-len) 之间迭代
//我们需要使用一段黑科技了
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&arr))
//cast to [cap]int
data := *(*[5]int)(unsafe.Pointer(hdr.Data))
//我们可以看到,底层的修改,已经成功了
fmt.Println(data[2]) //exampleFunc函数扩展的元素,idx = 2
}