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 关注
- 127 浏览
添加回答
举报