go中指针相等判断直接用==即可,只要类型相同且非nil,就比较是否指向同一内存地址;nil指针比较也安全;但接口或反射包装后需用reflect.value.pointer()还原地址比较。

Go 中指针相等判断直接用 == 就行
只要两个指针类型相同(比如都是 *int),且都非 nil,p1 == p2 判断的就是它们是否指向同一块内存地址——也就是同一个对象。这是 Go 语言规范明确支持的行为,不是巧合,也不是底层 trick。
常见错误现象:有人先对指针解引用再比较值,比如 *p1 == *p2,结果发现值相等却误以为指针也相等;或者把不同变量的地址强制转成 uintptr 再比,反而绕开类型安全还可能出错。
-
p1和p2必须是相同具体类型的指针(*string和*int不能比) - 如果任一为
nil,nil == nil是 true,但nil == p(p 非 nil)是 false —— 安全,无需额外判空 - 结构体字段指针、切片底层数组指针、map 的内部指针……只要能拿到指针变量本身,都适用这套规则
什么时候 == 会失效?小心接口和反射场景
当指针被装进 interface{} 或通过 reflect.Value 暴露时,直接比较接口值或反射值,== 不再比较地址,而是比较接口的动态类型+值,或者反射值的完整状态。
使用场景:比如你把 p1 和 p2 分别赋给两个 interface{} 变量,再拿这两个接口变量做 ==,结果几乎总是 false,哪怕它们原本指向同一对象。
立即学习“go语言免费学习笔记(深入)”;
- 接口变量比较:用
reflect.ValueOf(p1).Pointer() == reflect.ValueOf(p2).Pointer()才能还原地址比较 - 注意
reflect.ValueOf(&x).Pointer()要求 x 地址可取(不能是字面量、map/slice 元素等不可寻址值) - 若指针来自
unsafe.Pointer转换,确保转换路径合法,否则比较结果无意义
对比 reflect.DeepEqual:它不解决“是否同一对象”问题
reflect.DeepEqual 比的是两个值的**内容是否等价**,不是地址是否相同。对指针来说,它默认只比较指针所指的值,而不是指针本身——除非你传进去的是指针的指针(**T)。
容易踩的坑:有人想确认两个切片是否共享底层数组,就拿 reflect.DeepEqual(s1, s2),结果值一样就以为共用,其实完全可能是两份独立拷贝。
- 要确认切片是否同源,得比
reflect.ValueOf(s1).UnsafeAddr() == reflect.ValueOf(s2).UnsafeAddr()(仅限可寻址切片) -
reflect.DeepEqual对nil指针和空结构体表现特殊,和地址比较毫无关系 - 性能上,
==是常数时间汇编指令;reflect.DeepEqual是深度遍历,慢且有 panic 风险
真实调试中怎么快速验证两个指针是不是同一个
最稳的方式就是打日志输出地址,而不是靠脑补或间接推断。Go 标准库打印指针时默认显示地址,利用好这点。
示例:
fmt.Printf("p1=%p, p2=%p\n", p1, p2) 输出类似 p1=0xc000010230, p2=0xc000010230,地址一致就实锤了。
- 不要用
fmt.Sprintf("%v", p),它在某些情况下会尝试解引用并格式化值,掩盖地址信息 - 在测试里写断言:
if p1 != p2 { t.Fatal("expected same pointer") },比字符串匹配更可靠 - 注意:CGO 导出的指针、
unsafe构造的指针,%p仍可打印,但语义需你自己负责
== 这一行代码,而在它前面那几行你怎么拿到这两个指针的。










