Pointers 在Go中,结构指针不是引用类型吗?

Pointers 在Go中,结构指针不是引用类型吗?,pointers,go,struct,Pointers,Go,Struct,我不理解Go变量的行为。我要你告诉我。请参见下面的示例实现 包干管 进口 fmt func pointerip*Num{ fmt.Printfpointer类型[%T]:%p\n、&ip、&ip } func pointerpointerip**Num{ fmt.Printfpointerpointer类型[%T]:%p\n,ip,ip } func main{ pnum:=&Num{i:3} fmt.Printfmain类型[%T]:%p\n、&pnum、&pnum 指针数 指针和pnum }

我不理解Go变量的行为。我要你告诉我。请参见下面的示例实现

包干管 进口 fmt func pointerip*Num{ fmt.Printfpointer类型[%T]:%p\n、&ip、&ip } func pointerpointerip**Num{ fmt.Printfpointerpointer类型[%T]:%p\n,ip,ip } func main{ pnum:=&Num{i:3} fmt.Printfmain类型[%T]:%p\n、&pnum、&pnum 指针数 指针和pnum } 类型Num struct{ i int } 后果 我将struct Num指针存储为变量[pnum]。传递给指针函数时可以获取的地址与主函数中可以获取的地址不同。为什么

已经确认,通过将指针指针引用为指针指针函数,可以获得与主函数相同的地址。

pnum在main中是一个实际变量:一个浮动在内存中的框,包含*Num类型的指针

pnum指向什么?嗯,Num{i:3}创建了一个未命名的变量,浮动在内存中的某个地方。我们还没有打印出来。我想知道:

main type [**main.Num] : 0x40c138
pnum points to [*main.Num] : 0x40e020
或:

现在让我们继续:main调用指针,将存储在pnum中的值传递给它0x40c138值,该值让计算机找到包含未命名实例的框,该实例包含i=3。该值存储在内存中的某个位置。那在哪里?为什么,这是你打印的号码,因为你打印&ip。幸运的是,操场是非常确定的,所以它也是我打印的:

pointer type [**main.Num] : 0x40c148
因此,我们可以向图形中添加另一个框:

 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
                   ^
 0x40c148          |
+--------+         |
|0x40e020|---------+
+--------+
现在指针返回,丢弃保存0x40e020的0x40c148处的框,然后调用pointerpointer,将&pnum作为值传递。函数指针指针现在在某个位置运行时带有一个框。那个位置在哪里?我们不知道;我们从不打印它。我们在该位置打印框中的内容,框中的内容是0x40c138:

我们可以重新开始并运行:

pointerpointer's &ip is [***main.Num] : 0x40c150
因此,将八个问号替换为0x40c150

这里的总体规则很简单:每个变量都有一些存在的地方,除非编译器可以优化它。使用&x获取变量的地址,有助于防止编译器优化变量本身。x的类型是x的指针,其中空白是x的类型。&x的值是变量的地址

在这种情况下,你

创建了一个匿名的未命名Num实例, 将其地址强制编译器将其放入内存中的某个位置 将变量pnum设置为该值 都在第一行的主要。然后你取了pnum本身的地址,这意味着pnum也必须生活在内存中的某个地方。这是我们最初画的两个盒子。您在第二行打印了该地址的类型和值

然后将pnum中存储的值传递给func指针,func指针将该值存储在变量中。这样就创建了另一个单独的变量,它有自己的地址

不必担心函数指针做了什么,然后将pnum的地址传递给func pointer。此地址是一个值,指针指针将该值存储在变量中。这也创建了另一个单独的变量

在整个过程中,i=3的匿名Num的地址从未移动过。pnum的地址本身也是如此。

简短的回答是:

指针是按值传递的

函数指针接收内存地址的副本。它将副本存储在某个地方,可能是它自己的堆栈或其他东西

内存地址只是一个数字

如果您在main中定义一个数字并获取其地址,然后将该数字传递给另一个函数并获取其地址,您是否希望两个地址相同

在Go中,结构指针不是引用类型吗

不,只是因为Go中没有引用类型

有一些类型具有引用语义,切片是最突出的示例,但即使切片也是值类型而不是引用类型

指针在一个普通的值和真正的机器级地址。当你传递一个内存地址时,并没有任何引用。如果将内存地址存储在变量中,则可以获取该变量的地址。再也没有什么比这更重要的了。它的价值观一直在下降


基本上就像C中的一样。

非常感谢。加深了对内存中实际分配的十六进制值和地址的理解。这张详细的图表对我的理解很有帮助。顺便说一句,在过去,也许将来某一天,有些计算机不使用简单的线性寻址内存。Go应该能够在这样的系统上运行,但是,%p可能会打印两个十六进制数字,或者像C运行时系统在80286机器上使用分段内存所做的那样。我知道内存地址只是值。如果你可以的话,那会很有帮助的
告诉我更多关于引用语义的含义。现在,我认为引用语义和引用类型是相同的。下面是一个示例实现,其中slice是引用类型@TsujiDaishiro切片是一个数组的视图。视图本身是一个值:如果将长度为5的切片传递给函数,并且该函数将其切片副本缩短为长度3,则调用函数仍然具有长度为5的切片:作为视图的切片本身是一个值,并且被复制。您可以通过切片访问基础数组的元素,这是切片显示引用语义的地方:切片的单个元素(而不是切片本身)可能会被共享,因此其行为类似于引用。@TsujiDaishiro在您的示例中,main中的切片和pow中的副本都是与切片不同的值,但它们都是引用支持数组的相同元素。当您执行a[i]=a[i]*a[i]时,您不需要对切片本身做任何操作,而是需要操作支持数组的元素。后备阵列在main和pow之间共享。这就是为什么切片具有引用语义,因为使用切片的主要原因是访问支持数组的共享/引用元素。我理解切片是数组引用的概念。这很有帮助,因为我没有意识到这一点。我希望在编写代码时加深对详细行为的理解。非常感谢。
pointer type [**main.Num] : 0x40c148
 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
                   ^
 0x40c148          |
+--------+         |
|0x40e020|---------+
+--------+
 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
    ^
    |
 ????????
+--------+
|0x40c138|
+--------+
pointerpointer's &ip is [***main.Num] : 0x40c150