unsafe.Pointer 有什么用途?风险在哪里?

一句话结论:unsafe.Pointer 是“任意类型指针与 uintptr 之间的通用转换通道”,用来突破类型系统做底层操作:按内存布局重解释数据、零拷贝转换(如 string 与 []byte)、访问未导出字段、配合 cgo 与 syscall 等;代价是绕过编译期检查与 GC 的部分保护,可能依赖具体内存布局与编译器行为,可移植性差,非必要不用。

典型用途

  • 类型重解释:把一块内存按另一种类型读取,避免拷贝。
  • 零拷贝转换:string 与 []byte 互转不复制底层数组(需保证后续不可变)。
  • 访问结构体私有字段:基于已知的内存布局计算偏移。
  • 与 C/汇编/系统调用互操作时构造指针。
  • 实现高性能容器(如无锁队列的节点指针运算)。

转换规则要点

转换是否安全持有说明
*T → unsafe.Pointer → *U可以常见重解释方式,注意对齐与布局
*T → uintptr不可以长期持有uintptr 是整数,GC 不追踪、对象可能被回收
unsafe.Pointer → uintptr仅限同表达式内使用如 addr + offset 后立刻转回

关键点:uintptr 会被 GC 当作普通整数,不参与存活分析;把指针存成 uintptr 再稍后使用,对象可能已被回收,必须用 runtime.KeepAlive 等保住引用。

风险清单

  • 破坏封装:直接读写未导出字段,依赖内部布局,库一升级就崩。
  • 架构差异:结构体填充、对齐、大小端在不同平台不同。
  • GC 风险:指针转 uintptr 后丢失“引用”语义,可能悬垂。
  • 版本风险:编译器优化与运行时实现变化都可能改变假设。
  • 官方不承诺兼容:unsafe 用法“按当前实现工作”,不保证跨版本成立。
// 零拷贝 []byte -> string(前提:期间不再修改 b)
func b2s(b []byte) string {
	return unsafe.String(unsafe.SliceData(b), len(b))
}

// 危险示范:把指针存成 uintptr 后再用
// p := uintptr(unsafe.Pointer(&x)) // x 可能已被 GC 回收

常见追问 / 记忆点

  • 追问:unsafe.Pointer 和 uintptr 是一回事吗?——不是:前者是真正的指针类型,GC 认识;后者是整数,GC 不追踪。
  • 追问:标准库里哪里用了 unsafe?——strings.Builder 的 String、切片/字符串转换、sync.Pool 等底层实现都有。
  • 记忆点:unsafe 是“按当前实现可用”,不是契约;指针别转 uintptr 长期持有;能用安全写法就安全写。
笔记加载中…