這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
原文連結:There is no pass-by-reference in Go
我之前關於指標的那篇帖 引起了很多關於引用傳遞的爭議。這篇文章算是對這些爭議的回應吧。
首先要清楚的是: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 mainimport ( "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 mainimport "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 mainimport "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 語言中連引用變數也沒有。