能,但仅限于相同类型且指向同一内存地址的指针;== 比较的是地址值而非内容,nil 指针可安全比较,结构体字面量或函数返回值会导致地址不同而比较为 false。

Go 中两个指针能直接用 == 比较吗
能,但仅限于相同类型、且都指向堆或栈上同一块内存地址的指针。Go 的 == 对指针是按地址值比较的,不是按所指对象内容比较。
常见错误现象:对两个结构体指针用 == 判断“是否逻辑相等”,结果为 false,哪怕它们字段完全一样——因为地址不同。
- 只适用于
*T类型之间比较,不能混类型(比如*int和*int64不能比) - nil 指针之间可以安全比较:
p == nil是标准写法 - 如果指针是接口类型(如
interface{})包装的,==比较的是接口头,不是底层指针值,结果不可靠
什么时候 == 会意外返回 false
表面看是同一对象,但实际分配了多份内存,导致地址不同。最典型场景是结构体字面量或函数返回值带来的隐式拷贝。
示例:
立即学习“go语言免费学习笔记(深入)”;
type User struct{ ID int }
u1 := &User{ID: 1}
u2 := &User{ID: 1} // 新分配,地址不同
fmt.Println(u1 == u2) // false,哪怕字段一模一样
- 函数返回结构体再取地址:
func newU() User { return User{1} }; p1 := &newU(); p2 := &newU()→ 地址必然不同 - 切片/映射中存储的结构体,取出后取地址也会新建栈帧,地址不复用
- 反射获取的指针(如
reflect.Value.Addr())在某些情况下可能生成新指针,需谨慎
想判断“内容相同”该用什么
指针相等 ≠ 内容相等。需要深比较时,别碰 ==,改用 reflect.DeepEqual 或手动比较字段。
-
reflect.DeepEqual(p1, p2)可以处理*T,但注意它比较的是解引用后的值,且性能较差,不适合高频调用 - 如果结构体字段少且稳定,写个
Equal(*T, *T) bool方法更清晰、更快、可读性更强 - 切忌对含
func、map、slice(未规范初始化)的结构体盲目用DeepEqual,容易 panic 或行为异常
unsafe.Pointer 转换后还能用 == 吗
能,但风险极高,且不推荐。把两个指针转成 unsafe.Pointer 再比较,本质还是比地址,但绕过了类型检查。
- 转换本身不改变地址值,所以
unsafe.Pointer(p1) == unsafe.Pointer(p2)和p1 == p2结果一致(前提是转换合法) - 但如果其中一个是非法地址(比如已释放内存、越界),行为未定义,可能 crash 或静默出错
- 跨包或跨模块传递
unsafe.Pointer容易破坏内存安全模型,Go 1.22+ 对其使用有更严检查
真正需要地址级判断的场景极少,多数时候是设计上混淆了“身份”和“状态”。留心那些本该用唯一 ID 或版本号做判别的地方,别让指针相等性替你背锅。










