go可以看成增强版的C语言,因此也在一定程度上延续了C的一些特性。和C一样Go语言的函数调用参数全部是传值的,包括 slice/map/chan 在内所有类型,没有传引用的说法,传指针也是将指针的值拷贝一份。
那Go语言有传引用的说法吗?
Go语言其实也是有传引用的地方的,但是不是函数的参数,而是闭包对外部环境是通过引用访问的。
func main() {
a := new(int)
fmt.Println(a)
func() {
a = nil
}()
fmt.Println(a)
}
输出
0xc42000a3c8
<nil>
因为闭包是通过引用的方式使用外部环境的a变量, 因此可以直接修改a的值.
比如下面2段代码的输出是截然不同的, 原因就是第二个代码是通过闭包引用的方式输出i变量:
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
// Output: 4 3 2 1 0
}
fmt.Printf("\n")
for i := 0; i < 5; i++ {
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 5 5 5 5 5
}
像第二个代码就是于闭包引用导致的副作用, 回避这个副作用的办法是通过参数传值或每次闭包构造不同的临时变量:
// 方法1: 每次循环构造一个临时变量 i
for i := 0; i < 5; i++ {
i := i
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 4 3 2 1 0
}
// 方法2: 通过函数参数传参
for i := 0; i < 5; i++ {
defer func(i int){ fmt.Printf("%d ", i) } (i)
// Output: 4 3 2 1 0
}
我是咕咕鸡,一个还在不停学习的全栈工程师。
热爱生活,喜欢跑步,家庭是我不断向前进步的动力。