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