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

Tsu*_*iro 0 struct pointers go

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

package main

import (
    "fmt"
)

func pointer(ip *Num) {
    fmt.Printf("pointer type [%T] : %p\n", &ip, &ip)
}

func pointerpointer(ip **Num) {
    fmt.Printf("pointerpointer type [%T] : %p\n", ip, ip)
}

func main() {
    pnum := &Num{i: 3}
    fmt.Printf("main type [%T] : %p\n", &pnum, &pnum)
    pointer(pnum)
    pointerpointer(&pnum)
}

type Num struct {
    i int
}

Run Code Online (Sandbox Code Playgroud)

https://play.golang.org/p/LxDAgopxeh0

  • 结果
main type [**main.Num] : 0x40c138
pointer type [**main.Num] : 0x40c148
pointerpointer type [**main.Num] : 0x40c138
Run Code Online (Sandbox Code Playgroud)

我将struct Num指针存储为变量[pnum]。将其传递给指针函数时可以获取的地址与主函数中可以获取的地址不同。为什么??

已经确认,通过将指针指针称为指针指针功能,可以获得与主功能相同的地址。

tor*_*rek 5

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

 0x40c138
+--------+
|    *---|--->
+--------+
Run Code Online (Sandbox Code Playgroud)

为了什么呢pnum呢?好了,Num{i: 3}创建了一个未命名的变量,该变量漂浮在内存中的某个位置。我们还没有打印出来。我修改了您的Playground示例,添加了另一个fmt.Printf调用以查找:

main type [**main.Num] : 0x40c138
pnum points to [*main.Num] : 0x40e020
Run Code Online (Sandbox Code Playgroud)

要么:

 0x40c138       0x40e020
+--------+     +--------+
|    *---|---> |  i: 3  |
+--------+     +--------+
Run Code Online (Sandbox Code Playgroud)

现在,让我们继续前进:main通话pointer,传递给它的存储在pnum-the 0x40c138值,它可以让计算机在盒子拿着不知名的实例保存i=3。此值存储在内存中的某个位置。那是哪里 为什么,这是您打印的号码,因为您打印了&ip。幸运的是,游乐场是非常确定性的,所以它也是我打印的:

pointer type [**main.Num] : 0x40c148
Run Code Online (Sandbox Code Playgroud)

因此,我们可以在图形中添加另一个框:

 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
                   ^
 0x40c148          |
+--------+         |
|0x40e020|---------+
+--------+
Run Code Online (Sandbox Code Playgroud)

现在pointer返回,丢弃0x40c148保留的框0x40e020,然后调用pointerpointer,将其&pnum作为值传递。功能pointerpointer现在在某些位置带有一个框。那地方在哪 我们不知道 我们从不打印它。我们做打印什么是该位置的框,什么是箱子是0x40c138

 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
    ^
    |
 ????????
+--------+
|0x40c138|
+--------+
Run Code Online (Sandbox Code Playgroud)

我们可以向程序中再添加一个fmt.Printf,以查找最后一个框实际上在内存中的位置,然后再次运行:

pointerpointer's &ip is [***main.Num] : 0x40c150
Run Code Online (Sandbox Code Playgroud)

因此,用替换八个问号0x40c150

这里的总体规则很简单:每个变量都在某个地方存在,除非编译器可以对其进行优化。用来获取变量 的地址&x,往往会阻止编译器优化变量本身。该类型&xpointer to ___在毛坯的类型x。的&x是变量的地址。

在这种情况下,您

  • 做了一个匿名(未命名)Num实例,
  • 获取其地址(迫使编译器将其放入内存中的某个位置),然后
  • 将变量pnum设置为该值

(全部在的第一行中main)。然后,您获取了pnum自身的地址,这pnum也意味着它必须位于内存中的某个位置。那就是我们最初画的两个盒子。您在第二行上打印了该地址的类型和值。

然后,您将存储在中的值传递pnumfunc pointer,后者将值存储在变量中。这样就创建了另一个单独的变量,它具有自己的地址。

而不用担心功能pointer做了,你再通过地址pnumfunc pointerpointer。该地址是一个值,并将pointerpointer该值存储在变量中。这也创建了另一个单独的变量。

纵观这一切,匿名的地址Numi=3一动也不动。pnum本身的地址也没有。