You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中以结构体指针为键的map工作原理及输出疑问

为什么用空结构体指针作为map键时只输出一个条目?

嘿,这个问题的核心在于Go对空结构体指针的特殊优化处理!我来一步步给你拆解:

1. 空结构体的内存特性

你的结构体A是一个空结构体:type A struct{},它的内存大小是0字节——因为它没有任何字段需要存储数据。Go的编译器和运行时为了节省内存,会做一个非常聪明的优化:所有指向空结构体的指针,都会指向同一个内存地址。

也就是说,你代码里的a1 := &A{}、a2 := &A{}、a3 := &A{},看起来是三个不同的变量,但它们实际指向的是同一个内存地址,本质上是同一个指针!

2. map键的相等性判断

Go里的map判断两个键是否相等,对于指针类型来说,是看它们的内存地址是否完全一致。因为a1、a2、a3是同一个指针,所以你三次给map赋值的操作:

m2[a1] = "hello"
m2[a2] = "world"
m2[a3] = "!"

其实都是在给同一个键赋值,后面的值会直接覆盖前面的。最后map里就只剩一个键值对:&{} -> "!"。

3. 验证这个结论

你可以在代码里加上指针地址的打印,就能直观看到这个优化:

package main

import "fmt"

type A struct{}

func main() {
	a1 := &A{}
	a2 := &A{}
	a3 := &A{}
	// 打印三个指针的地址,会发现它们完全相同
	fmt.Printf("a1地址: %p\n", a1)
	fmt.Printf("a2地址: %p\n", a2)
	fmt.Printf("a3地址: %p\n", a3)

	m2 := make(map[*A]string)
	m2[a1] = "hello"
	m2[a2] = "world"
	m2[a3] = "!"
	for k, v := range m2 {
		fmt.Println(k, v)
	}
}

4. 如何避免这个情况?

如果你希望每个指针都是独立的map键,只需要给结构体A添加至少一个字段(哪怕是一个不需要使用的字段),比如:

type A struct {
	// 随便加一个字段,让结构体占用非0内存
	Dummy int
}

这样每个&A{}都会分配独立的内存地址,map里就会保留三个不同的键值对,遍历的时候就能看到所有输出了。

内容的提问来源于stack exchange,提问作者o0omycomputero0o

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:17:37