跳到主要内容

Pin 与 Unpin

问题

Pin 解决了什么问题?什么时候需要关心它?

答案

Pin<P> 保证指针 P 指向的值不会被移动。这主要是为了支持自引用结构体——async/await 生成的 Future 状态机可能包含自引用。

详细的 Pin 机制和 Future 的交互请参考 Future trait 与 Pin

快速入门

use std::pin::Pin;

// 大多数类型是 Unpin 的,Pin 对它们没有限制
let mut x = 42;
let pinned = Pin::new(&mut x); // ✅ i32: Unpin

// async 生成的 Future 可能是 !Unpin
async fn example() {
let data = vec![1, 2, 3];
let r = &data;
some_op().await; // await 点 → 可能自引用
println!("{:?}", r);
}

// 需要 Pin 才能 poll
let future = example();
// future 必须被 Pin 住才能安全 poll
let pinned = Box::pin(future);

实际使用

在日常 async 代码中,你几乎不需要直接操作 Pin——.await 和运行时会自动处理。需要手动处理 Pin 的场景:

  1. 手动实现 Future trait
  2. 返回 Pin<Box<dyn Future>>
  3. 编写侵入式链表等自引用数据结构
// 常见用法:动态分发的 Future
fn choose(flag: bool) -> Pin<Box<dyn Future<Output = i32> + Send>> {
if flag {
Box::pin(async { 1 })
} else {
Box::pin(async { 2 })
}
}

常见面试问题

Q1: 如果移动一个自引用结构体会怎样?

答案

内部的指针/引用会变成悬垂指针,指向旧地址。这就是为什么需要 Pin——它保证值不会被移动,从而保证自引用的有效性。

Q2: Unpin 是什么意思?

答案

Unpin 意味着"即使被 Pin 了也可以移动"。大多数普通类型自动实现 Unpin。只有自引用结构体(如 async Future)才需要是 !Unpin 的,此时 Pin 才真正限制移动。

相关链接