1.13 引用类型与指针,有什么不同?¶
切片是一个引用类型,将它作为参数传入函数后,你在函数里对数据作变更是会实时反映到实参切片的。
func foo(s []int) {
s[0] = 666
}
func main() {
slice := []int{1,2}
fmt.Println(slice) // [1 2]
foo(slice)
fmt.Println(slice) // [666 2]
}
此时切片这一引用类型,是不是有点像指针的效果?是的。
但它又和指针不一样,这一点主要体现在:在形参中所作的操作并不一定都会反映在实参上。
还是以切片为例,我在形参上对切片进行扩容,发现形参扩容后,实参并没有发生改变。
func foo(s []int) {
s = append(s, 666)
}
func main() {
slice := []int{1,2}
fmt.Println(slice) // [1 2]
foo(slice)
fmt.Println(slice) // [1 2]
}
这是为什么呢?
这是因为当你对一个切片 append 的时候,它会做这些事情:
新建一个新的切片 slice2,其实长度与 slice1 一样,但容量是 slice1 的两倍,此时 slice2 底层指向的匿名数组和 slice1 不是同一个。
将 slice1 底层的数组的元素,一个一个的拷贝给 slice2 底层的数组。
并把扩容的元素也拷贝到 slice2中
最后把新的 slice2 返回回来,这就是为什么指针不用返回,而 slice.append 也要返回的原因
从这个流程中,可以看到等号左边的 s (slice2)和 等号右边的 s (slice1)底层引用的数组已经不是同一个了
s = append(s, 666)
因此切片的形参做扩容,并不会影响到实参。