1.14 Go 是值传递,还是引用传递、指针传递?

Golang中函数的参数为切片时是传引用还是传值?

对于这个问题,可能会有很多认为是传引用,就比如下面这段代码

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]
}

如果你不了解 Go 中切片的底层结构,你很可能会误信上面的观点。

但其实不是,Go语言中都是值传递,而不是引用传递,也不是指针传递

Go 中切片的底层结构是这样的

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

而当你将切片作为实参传给函数时,函数是会拷贝一份实参的结构和数据,生成另一个切片,实参切片和形参切片,不仅是长度、容量相等,连指向底层数组的指针都是一样的。

通过分别打印实参切片和形参切片的指针地址,就能验证这一观点

func foo(s []int)  {
    fmt.Printf("%p \n", &s) // 0xc00000c080
    s = append(s, 666)
}

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