初始化了一个map型的变量m,使用printf(%p)的格式分别对m和&m进行输出,分别得到两个地址。
&m显而易见是m变量的地址,令我困惑的是m也可以输出一个地址,但有人说m保存的并非指针,那为什么m却可以输出地址?map类型的变量访问的机制是什么样的?谢谢
初始化了一个map型的变量m,使用printf(%p)的格式分别对m和&m进行输出,分别得到两个地址。
&m显而易见是m变量的地址,令我困惑的是m也可以输出一个地址,但有人说m保存的并非指针,那为什么m却可以输出地址?map类型的变量访问的机制是什么样的?谢谢
2 回答2.4k 阅读✓ 已解决
1 回答2.4k 阅读✓ 已解决
2 回答1.7k 阅读✓ 已解决
1 回答1.2k 阅读✓ 已解决
1 回答1.4k 阅读✓ 已解决
2 回答1.2k 阅读
1 回答1.8k 阅读
要明白这个问题只能追追源码了。
可以看下 map 的初始化函数 make 的源码。make 可用于 map、slice、chan 三种类型,每个类型都有相应的 make 实现,比如,map 的 make 实现在源码文件 src/runtime/map.go 中。我贴下相应的代码片段,如下:
注意下,makemap_small 的返回值,它是一个指针,而不是具体的结构体,当这里也就明白了 fmt.Printf 打印的为什么是指针而不是具体某个值了。至于为什么不像 slice 那样直接返回结构体呢,我想或许是因为 hmap 的成员字段比较多吧。
到这里,问题似乎差不多都明白了,但我还发现一个问题。什么问题呢?为什么 slice 用 fmt.Printf(%p) 也是打印的指针,明明 make slice 返回的是结构体啊。slice 的 make 源码目录在 src/runtime/slice.go 中,相应代码如下:
的确返回的是 slice 结构体,而不是指针。那为什么 fmt.Printf(%p) 返回的是指针呢?这个问题要看下 fmt.Printf 的源码了,文件位置在 src/fmt/print.go,%p 的处理代码如下:
当为 p 格式时,执行指针格式化函数 fmtPointer,为什么 slice 的 Printf 打印的是指针,奥秘就是 value.Pointer 中,进去看下源码,如下:
从代码可以看出,当打印的类型是 Slice 时,通过 Pointer 获取到的值是 Slice 底层数组的地址。
到此,你就应该全部明白了,为什么 map 和 slice 打印的都是地址,而不是它们的结构体。