
在 Go 中,可直接用 == 比较两个指针是否指向同一内存地址;但若指针源自值接收器方法中的局部副本,则它们必然不等——这是因地址来自不同变量实例,而非内容差异。
在 go 中,可直接用 `==` 比较两个指针是否指向同一内存地址;但若指针源自值接收器方法中的局部副本,则它们必然不等——这是因地址来自不同变量实例,而非内容差异。
Go 语言中,指针的相等性(==)语义非常明确:两个指针相等当且仅当它们指向同一个内存地址(或同为 nil)。这正是判断“是否指向同一对象”的标准、高效且推荐的方式——无需反射、无需 unsafe,更无需解引用比较内容。
然而,如下面代码所示,看似指向“同一个 Map”的两个指针却比较失败:
type Map struct{}
type Fragment struct {
Map *Map
}
func (m1 Map) NewFragment() (f Fragment) {
f.Map = &m1 // ⚠️ 注意:m1 是 m 的副本!
return
}
var m Map = Map{}
func main() {
f := m.NewFragment()
fmt.Println(f.Map == &m) // false —— 地址不同
fmt.Println(*f.Map == m) // true —— 值相同(因为 Map 是空结构体,且值接收器复制了 m)
}问题根源在于方法接收器类型:func (m1 Map) NewFragment() 使用的是值接收器,这意味着调用时 m 会被完整复制一份到栈上,命名为 m1;&m1 获取的是这个临时副本的地址,而 &m 是原始变量 m 的地址——二者内存位置完全不同,因此 f.Map == &m 必然为 false。
✅ 正确做法:若需让方法返回指向原始对象的指针,应改用指针接收器:
func (m1 *Map) NewFragment() Fragment {
return Fragment{Map: m1} // 直接传递原始地址
}
// 调用需使用指针:
mPtr := &m
f := mPtr.NewFragment()
fmt.Println(f.Map == &m) // true ✅⚠️ 注意事项:
- 空结构体(如
struct{}或本例中的Map)的值比较恒为true,但这与指针相等性无关,切勿混淆; -
==对指针安全、高效、符合 Go 规范;不要尝试用reflect.ValueOf(p).Pointer()或unsafe绕行——既不必要,也破坏类型安全; - 若需在接口或泛型场景下统一处理指针/非指针,应显式设计 API 约束(如要求传入
*T),而非依赖运行时判断。
总结:Go 中判断“是否同一地址”,就用 p1 == p2;而指针不等的根本原因,往往不在比较操作本身,而在指针的来源是否真正关联同一变量实例——检查接收器类型、变量作用域和复制行为,才是调试此类问题的关键。

















