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

标签 pointers go struct

我不明白 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
}

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

  • 结果
main type [**main.Num] : 0x40c138
pointer type [**main.Num] : 0x40c148
pointerpointer type [**main.Num] : 0x40c138

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

已经证实,通过指针指针函数的引用,可以得到与main函数相同的地址。

最佳答案

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

 0x40c138
+--------+
|    *---|--->
+--------+

pnum 指向什么?好吧,Num{i: 3} 创建了一个未命名的变量,它漂浮在内存中的某个地方。我们还没有打印出来。我 modified your Playground example to add one more fmt.Printf call找出:

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

或:

 0x40c138       0x40e020
+--------+     +--------+
|    *---|---> |  i: 3  |
+--------+     +--------+

现在让我们继续:main 调用 pointer,将存储在 pnum 中的 value 传递给它—— 0x40c138 值,它让计算机找到包含未命名实例的盒子,该实例包含 i=3。该值存储在某处的内存中。那是什么地方?为什么,这是你打印的数字,因为你打印了&ip。幸运的是 Playground 是非常确定的,所以它也是我打印的:

pointer type [**main.Num] : 0x40c148

所以我们可以在绘图中添加另一个框:

 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
                   ^
 0x40c148          |
+--------+         |
|0x40e020|---------+
+--------+

现在 pointer 返回,丢弃位于 0x40c148 处的框,其中包含 0x40e020,您调用 pointerpointer,传递&pnum 作为一个值。函数 pointerpointer 现在在某个位置运行一个框。那个位置在哪里?我们不知道;我们从不打印它。我们在那个位置打印盒子里的,盒子里的0x40c138:

 0x40c138       0x40e020
+--------+     +--------+
|0x40e020|---> |  i: 3  |
+--------+     +--------+
    ^
    |
 ????????
+--------+
|0x40c138|
+--------+

我们可以add one more fmt.Printf to the program to find where this last box actually is in memory再次运行:

pointerpointer's &ip is [***main.Num] : 0x40c150

所以用 0x40c150 替换八个问号。

这里的总体规则很简单:每个变量都存在于某处,除非编译器可以将其优化掉。获取变量的地址,使用&x,往往会阻止编译器优化变量本身。 &x类型指向___ 的指针,其中空白是x 的类型。 &x 是变量的地址。

在这种情况下,你

  • 制作了一个匿名(未命名)Num 实例,
  • 获取它的地址(强制编译器将它放入内存中的某个地方),然后
  • 将变量 pnum 设置为该值

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

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

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

在所有这些过程中,i=3 的匿名Num 的地址从未移动过。 pnum 本身的地址也没有。

关于pointers - 在 Go 中,结构指针不是引用类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59041891/

相关文章:

c++ - 涉及指针和手动实现的矩阵类的问题

go - 如何将变量 ID 传递给 golang 中的 statement.Query()?

C# - 值类型等于方法 - 为什么编译器使用反射?

C# 抽象结构

c - 从 void * 数组获取值

c++ - C 或 C++ 中的函数类型

c++ - 声明一个新节点但不等于 NULL

json - 将 JWT 负载转换回结构

mysql - 从sql文件加载存储过程

c - 如何接受字符数组输入到 C 结构中?