看完了Golang的官方教程,在处理Slice和Map的参数传递时还是会出现莫名奇妙的问题,原因在于还是没有弄清楚Golang的参数传递

我之前模糊地认为基本数据类型、数组、结构体是值拷贝(这几种类型未经初始化,默认零值),而切片、Map等是引用传递(这些类型没初始化就是nil),这个错误结论可能是由于我没有把写Java的习惯撇干净,经过了各种实验,我最后发现:Golang没有引用传递,所有的传参都是值拷贝

以切片为例

第一个函数

package main
import "fmt"

func modify_01(s []int) {
	s[0] = 999
}

func main() {
	s := make([]int, 3, 5)
	fmt.Println("Before", s)

	modify_01(s)
	fmt.Println("01 -->", s)
}

执行结果是

Before [0 0 0]
01 --> [999 0 0]

第二个函数

package main
import "fmt"

func modify_02(s []int) {
	s = make([]int, 3)
    s[0] = 7
    s[1] = 7
    s[2] = 7
}

func main() {
	s := make([]int, 3, 5)
	fmt.Println("Before", s)

	modify_02(s)
	fmt.Println("02 -->", s)
}

执行结果是

Before [0 0 0]
02 --> [0 0 0]

第三个函数

package main
import "fmt"

func modify_03(s []int) {
	s = append(s, 7)
}

func main() {
	s := make([]int, 3, 5)
	fmt.Println("Before", s)

	modify_03(s)
	fmt.Println("03 -->", s)
}

执行结果是

Before [0 0 0]
03 --> [0 0 0]

可以看出,同样是把切片传入函数,然后修改切片,modify_01 修改成功,modify_02modify_03 修改失败了。

因为切片作为参数是拷贝了切片的地址,modify_01 中的切片还是原来的切片;modify_02s 赋予了新的地址,做出的修改当然是不会反映在 main 函数里了;modify_03 虽然没有改变切片地址,但是在使用了 append 方法后,切片的len+1,那么切片已经不是原来的切片了,所以做出的修改也不会反映在 main 函数里。用图更好解释:(S’ 是指 S 的拷贝)

modify_01

Map也是同理,所以对于值拷贝的参数传递,如果要在函数内对它做修改,就要传递指针,类似这样

package main
import "fmt"

func modify_02(s *[]int) {
	*s = make([]int, 3)
	(*s)[0] = 7
	(*s)[1] = 7
	(*s)[2] = 7
}

func main() {
	s := make([]int, 3, 5)
	fmt.Println("Before", s)

	modify_02(&s)
	fmt.Println("02 -->", s)
}

执行结果是

Before [0 0 0]
02 --> [7 7 7]