我之前关于指针的那篇帖 引起了很多关于引用传递的争议。这篇帖子算是对这些争议的回应吧。
首先要清楚的是:Go 语言中没有引用变量,所以 Go 语言就没有引用传递的函数调用的语法。
什么是引用变量?
在像 C++ 这样的语言中你可以给一个已经存在的变量定义一个别名,这个别名就被称为引用变量。
#include <stdio.h>
int main() {
int a = 10;
int &b = a;
int &c = b;
printf("%p %p %p\n", &a, &b, &c); // 0x7ffe114f0b14 0x7ffe114f0b14 0x7ffe114f0b14
return 0;
}
你可以看到上面 a、b、c 都指向了相同的内存地址,向 a 写入数据将会更改 b、c 的内容。这当你想在不同作用域(即函数调用)里定义引用变量的时候就显得十分的关键。
Go 语言中并没有引用变量
与 C++ 不同,Go 语言中每一个定义的变量都占据一个唯一的内存地址
dave 原来的例子我觉得可能跟上面 C++ 的例子对比不是很突出,所以我改了一下
package main
import (
"fmt"
)
func main() {
var a int
var b = &a
var c = &a
fmt.Println(&a, &b, &c) //0xc0420361d0 0xc04204e018 0xc04204e020
}
在 Go 语言中,不可能创建 2 个变量而这 2 个变量却拥有相同的内存地址。Go 语言是允许创建 2 个变量它们的内容是同一个指向相同地址的指针,但是这与两个变量共享同一个内存地址完全是两回事。
package main
import "fmt"
func main() {
var a int
var b, c = &a, &a
fmt.Println(b, c) // 0x1040a124 0x1040a124
fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}
在这个例子中 b、c 持有的相同的值是 a 的地址,然而 b、c 他们自己的存储则存储在各自唯一的地址中的,更新 b 的内容 是不会对 c 的内容产生影响的。
但 Maps 与 Channels 是引用变量总该对了吧?
错! Maps 与 Channels 依然不是引用变量。如果他们是引用变量,那么下面这段程序将打印 false.
package main
import "fmt"
func fn(m map[int]int) {
m = make(map[int]int)
}
func main() {
var m map[int]int
fn(m)
fmt.Println(m == nil)
}
如果 m 像 C++ 那样是引用变量,定义在 fn 中的 m 与 定义在 main 中的 m 应该占用同一个内存地址,但是因为在 fn 中的赋值操作,并没有影响到 main 中 m 的值,所以我们可以看出 map 并不是引用变量。
结论:
Go 语言中并没有引用传递,因为在 Go 语言中连引用变量也没有。