3 回答

TA貢獻1852條經驗 獲得超1個贊
pnum中的main是一個實際變量:一個浮動在內存中的盒子,包含類型為 的指針*Num。
0x40c138
+--------+
| *---|--->
+--------+
指向什么pnum?好吧,Num{i: 3}創建了一個未命名的變量,漂浮在內存中的某個地方。我們還沒有打印出來。我修改了您的 Playground 示例,添加了一個fmt.Printf調用來找出答案:
main type [**main.Num] : 0x40c138
pnum points to [*main.Num] : 0x40e020
或者:
0x40c138 0x40e020
+--------+ +--------+
| *---|---> | i: 3 |
+--------+ +--------+
現在讓我們繼續:main調用,將存儲在中的值pointer傳遞給它—該值讓計算機找到包含未命名實例的盒子。該值存儲在內存中的某個位置。那是在什么地方?為什么,這是您打印的數字,因為您打印了。幸運的是,Playground 具有很強的確定性,所以它也是我打印的:pnum0x40c138i=3&ip
pointer type [**main.Num] : 0x40c148
所以我們可以在繪圖中添加另一個框:
0x40c138 0x40e020
+--------+ +--------+
|0x40e020|---> | i: 3 |
+--------+ +--------+
^
0x40c148 |
+--------+ |
|0x40e020|---------+
+--------+
現在返回,丟棄保存 的pointer框,然后調用,作為值傳遞。函數現在在某個位置與一個框一起運行。那個位置在哪里?我們不知道;我們從不打印它。我們確實在該位置打印了盒子里的東西,盒子里的東西是:0x40c1480x40e020pointerpointer&pnumpointerpointer0x40c138
0x40c138 0x40e020
+--------+ +--------+
|0x40e020|---> | i: 3 |
+--------+ +--------+
^
|
????????
+--------+
|0x40c138|
+--------+
我們可以在程序中再添加一個,fmt.Printf以查找最后一個框在內存中的實際位置,然后再次運行:
pointerpointer's &ip is [***main.Num] : 0x40c150
因此將八個問號替換為0x40c150。
這里的總體規則很簡單:每個變量都在某個地方存在,除非編譯器可以優化它。 使用 獲取變量的地址&x
往往會阻止編譯器優化變量本身。的類型,其中&x
空白pointer to ___
是 的類型x
。的值是變量&x
的地址。
在這種情況下,你
創建了一個匿名(未命名)
Num
實例,獲取它的地址(強制編譯器將其放入內存中的某個位置),并且
將變量設置
pnum
為該值
(全部在第一行main
)。然后你獲取了它本身的地址pnum
,這意味著它pnum
也必須存在于內存中的某個地方。這是我們最初畫的兩個盒子。您在第二行打印了該地址的類型和值。
然后,您將存儲在的值傳遞給pnum
,func pointer
后者將該值存儲在變量中。這樣就創建了另一個單獨的變量,它有自己的地址。
不用擔心函數pointer
做了什么,然后您將地址傳遞pnum
給func pointerpointer
。該地址是一個值,并將pointerpointer
該值存儲在變量中。這也創建了另一個單獨的變量。
在這整個過程中,匿名者的地址從未動Num
過i=3
。地址pnum
本身也沒有。

TA貢獻1966條經驗 獲得超4個贊
簡短的回答是:
指針通過值傳遞。
該函數pointer
接收內存地址的副本。它將副本存儲在某個地方(可能是它自己的堆?;蚱渌麞|西)。
內存地址只是一個數字。
如果您定義一個數字main
并獲取其地址,然后將該數字傳遞給另一個函數并獲取其地址,您是否應該期望兩個地址相同?

TA貢獻1804條經驗 獲得超2個贊
在Go中,結構體指針不是引用類型嗎?
不,只是因為Go中沒有 引用 類型。
有幾種類型具有引用語義,切片是最突出的例子,但即使切片也是值類型而不是引用類型。
Go 中的指針是普通值和真正的機器級地址。當您傳遞內存地址時,不會發生“引用內容”。如果將內存地址存儲在變量中,則可以獲取該變量的地址。再次沒有類似的參考。在 Go 中它的值一直向下。
基本上就像C中的一樣。
- 3 回答
- 0 關注
- 172 瀏覽
添加回答
舉報