Pin 的存在是为了解决自引用问题
Future
trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}Stream 又名 AsyncIterator,也就是一个可以被重复拉取的 Future,
以 Option 是否为 None 判定该 Stream 是否结束。
trait Stream {
type Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
}将字段包装为 Pin 类型
假设有这样的结构体
struct Foo {
bar: Bar,
baz: Baz,
}在为一个 Foo 实现 Future 或 Stream 时,
虽然接收器是 self: Pin<&mut Self>,但是我们只能拿到 bar 字段的可变引用 &mut Bar,
如果需要调用它的 poll 方法,就需要将这个字段包装为 Pin<&mut Bar> 类型。
使用 pin-project / pin-project-lite 投影
pin-project 采用过程宏实现。
use pin_project::pin_project;
#[pin_project]
struct Foo {
#[pin]
bar: Bar,
// 这个字段不会被自动包装为 `Pin`
baz: Baz,
}pin-project-lite 轻量级版本,采用声明宏实现。
use pin_project_lite::pin_project;
pin_project! {
struct Foo {
#[pin]
bar: Bar,
// 这个字段不会被自动包装为 `Pin`
baz: Baz,
}
}这两个宏都可以自动为结构体生成 project 方法,
该方法返回一个匿名枚举类型,其中包含了所有字段的引用,
其中 #[pin] 属性会自动该字段包装为 Pin 类型。
let this = self.project();
let bar: Pin<&mut Bar> = this.bar;
let baz: &mut Baz = this.baz;注意:以上的 project 表示将 Pin<&mut Self> 投影为 (Pin<&mut Bar>, &mut Baz)。
它的含义是「投影」,而不是「项目」。
因此正确读音是 /prəˈdʒɛkt/ 而不是 /ˈprɒdʒɛkt/。