
用 == 直接比较两个 *T 指针是否相等
Go 中指针的相等性判断非常直接:只要两个 *T 类型指针指向同一块内存地址,== 就返回 true。这和 C 不同,Go 不允许指针与整数互转,也不支持指针算术,所以不存在“绕过类型系统比地址”的需求。
常见错误是误以为需要 reflect.ValueOf(p).Pointer() 或 unsafe.Pointer 才能比较——完全没必要。Go 的 == 对指针就是按底层地址比较的。
- 必须是相同类型的指针才能用
==,比如*int和*string不能比较,编译报错:mismatched types *int and *string - nil 指针之间可以比较:
var a, b *int; a == b是true - 指向不同变量的指针,即使值相同,地址也不同:
var x, y int = 42, 42; &x == &y是false
为什么不能用 reflect.DeepEqual 判断指针是否同址
reflect.DeepEqual 比的是“值语义”而非“地址语义”。它会递归展开指针所指向的值来比较,不是看它们是不是同一个对象。
比如两个不同 int 变量都存 100,它们的指针传给 reflect.DeepEqual 会返回 true,但这完全违背了“判断是否同址”的初衷。
立即学习“go语言免费学习笔记(深入)”;
- 场景误用典型:想确认两个结构体字段是否引用同一底层数据,却用了
reflect.DeepEqual,结果掩盖了 aliasing 问题 - 性能影响明显:DeepEqual 要反射遍历整个值,而
==是单次机器字比较 - 对 map/slice/channel 等引用类型,
reflect.DeepEqual还可能 panic(如含 NaN 的 float)
当需要跨类型比较地址时:用 unsafe.Pointer 强转再比
极少数情况,你确实需要比较不同类型的指针是否指向同一地址(例如调试内存布局、实现自定义缓存键),这时必须借助 unsafe.Pointer。
注意:这不是常规做法,且禁止在非 unsafe 包或生产核心逻辑中滥用。
- 先转成
unsafe.Pointer,再转成uintptr,最后用==比较:uintptr(unsafe.Pointer(p1)) == uintptr(unsafe.Pointer(p2)) - 不能直接比较
unsafe.Pointer(p1) == unsafe.Pointer(p2),因为 Go 规定unsafe.Pointer本身不可比较 - 这种转换绕过了类型安全,如果 p1/p2 来自不同分配周期(如一个栈上一个堆上),结果可能无意义
容易被忽略的边界:interface{} 包装后的指针相等性
把指针存进 interface{} 后再拿出来,== 依然能正确比较地址——前提是类型没变。
但一旦发生类型断言失败、或 interface{} 里存的是指针的副本(比如通过值接收方法隐式复制),就容易误判。
- 正确:
var p *int; i := interface{}(p); i.(interface{}) == interface{}(p)→true - 陷阱:函数参数是
func f(v interface{}),传入&x,但在函数内做了v = &someOther,后续比较就失效了 - 更隐蔽的坑:用
sync.Map.Load存指针后取出,若 key 不匹配导致取到 nil,和另一个 nil 指针比较看似合理,实则混淆了“未找到”和“明确为 nil”










