1.11 为什么传参使用切片而不使用数组?

Go里面的数组是值类型,切片是引用类型。

值类型的对象在做为实参传给函数时,形参是实参的另外拷贝的一份数据,对形参的修改不会影响函数外实参的值。

因此在如下例子中两次打印的指针地址是不一样的

package main

import "fmt"

func arrayTest (x [2]int) {
    fmt.Printf("%p \n", &x)  // 0xc0000b4030
}

func main() {
    arrayA := [2]int{1,2}
    fmt.Printf("%p \n", &arrayA) // 0xc0000b4010
    arrayTest(arrayA)
}

假想每次传参都用数组,那么每次数组都要被复制一遍。如果数组大小有 100万,在64位机器上就需要花费大约 800W 字节,即 8MB 内存。这样会消耗掉大量的内存。

引用类型,则没有这个拷贝的过程,实参与形参指向的是同一块内存地址

package main

import "fmt"

func sliceTest (x []int) {
    fmt.Printf("%p \n", x)
}

func main() {
    sliceA := make([]int, 0)
    fmt.Printf("%p \n", sliceA)
    sliceTest(sliceA)
}

由此我们可以得出结论:

把第一个大数组传递给函数会消耗很多内存,采用切片的方式传参可以避免上述问题。切片是引用传递,所以它们不需要使用额外的内存并且比使用数组更有效率。

那么你肯定要问了,数组指针也是引用类型啊,也不一定要用切片吧?

确实,传递数组指针是可以避免对值进行拷贝的内存浪费。