pointers - 为什么所有嵌套的结构体对象在打印出来时都有相同的地址?

标签 pointers go

我试图在a := b中找出a是否是结构的不同副本,例如func pass_by_value(a some_struct)

但是我发现我不明白打印语句。

考虑这个go playground

    nested_level2 := test_assign_nested_level2{}
    nested_level1 := test_assign_nested{nested_level2}
    top_level := test_assign{nested_level1}

    assign := top_level
    fmt.Println("top_level address")
    fmt.Printf("%p", &top_level)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &top_level.Level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &top_level.Level1.Level_2)
    fmt.Println("------------------------")

    fmt.Println("assign top_level address")
    fmt.Printf("%p", &assign)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &assign.Level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &assign.Level1.Level_2)

上面的输出是

top_level address
0x10410020 
1 level address
0x10410020 
2 level address
0x10410020 
assign top_level address
0x10410024 
1 level address
0x10410024 
2 level address
0x10410024

我希望输出类似于

    fmt.Println("top_level address")
    fmt.Printf("%p", &top_level)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &nested_level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &nested_level2)
    fmt.Println(" ")
    fmt.Println(" ------------------------------- ")

哪里

top_level address
0x421152280 
1 level address
0x421152270 
2 level address
0x421152260 

每个结构体都有不同的地址。但子结构似乎与父结构具有相同的地址。

为什么结构体中的所有嵌套元素都有相同的地址?

:= 实际上会递归地复制一个新的 struct 吗?就像打印语句所示的那样? (即 := 将返回一个全新的结构副本,其每个字段内容也是递归的全新副本)

最佳答案

Go 中的类型不是其他事物的自主包装器,而只是两件事:类型允许附加方法,类型提供内存中的布局。对于这里的问题,将方法附加到类型的能力是无关紧要的。让我们看一下这个问题的中立表述:

type A int64
type B { a A }
type C { b B }

这声明了具有以下内存布局的三种类型:

  • 类型 A 具有 int64 的内存布局(即 8 个字节)。
  • 类型 B 具有单个 A 的内存布局,即 int64,即 8 个字节。
  • C 型具有单个 B 的内存布局,即单个 A,即 int64,因此 8 个字节。

关于内存布局,B 类型不是 A 的“包装器”,至少包装器绝对没有添加任何内容。从纯粹的内存布局角度来看,定义类型 B 是没有用的(但它允许将不同的方法附加到 B 而不是 A)。

现在应该清楚了,c C 的地址是其 8 个字节中的第一个字节,这与 c.b 的地址相同,而 c.b.a 的地址也相同。对 C 的任何赋值都只是一个机器字的副本(在 64 位架构上)。

如果您定义type D { a A; b B } 它变得更有趣,因为 D 现在是 16 字节长。 (向 D 添加更多内容甚至可能会因填充而留下漏洞。)但是 D 仍然没有为内存中彼此相邻的 A 和 B 提供任何内容(期望新的方法集)。

关于pointers - 为什么所有嵌套的结构体对象在打印出来时都有相同的地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46313250/

相关文章:

C 只打印数组的第一个字符,不打印其余字符?

C sizeof 字符指针

c++ - typedef 函数指针?

PostgreSQL:关系不存在错误

amazon-web-services - Golang : mocking AWS services which have same method name

c - 如何增加指针值数组的索引?

c++ - 向任何指针添加字节偏移的便携且安全的方法

go - 在 golang 中 slice unicode/ascii 字符串?

从服务器角度进行 HTTP 跟踪

sockets - 为什么在并发连接到服务器时接受两个相同的 5 元组套接字?