You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在await Future引用前需要先对其执行Pin操作?

为什么await Future的引用前必须进行Pin操作?

在使用Tokio的select!时会遇到一个规则:如果要.await一个Future的引用,被引用的Future必须被Pin住,或者实现了Unpin trait。比如下面的代码就无法编译:

let fut = example(); // example 是一个 async 函数
(&mut fut).await;

对应的编译错误信息如下:

error[E0277]: `from_generator::GenFuture<[static generator@src/main.rs:15:27: 17:2]>` cannot be unpinned
... snip ...
within `impl futures::Future<Output = i32>`, the trait `Unpin` is not implemented for `from_generator::GenFuture<[static generator@src/main.rs:15:27: 17:2]>`
... snip ...
note: consider using `Box::pin`

而对Future执行Pin操作后,代码就能正常编译运行:

let fut = example(); // example 是一个 async 函数
tokio::pin!(fut);
(&mut fut).await;

核心原因:Future的状态机特性与内存安全

async函数生成的Future本质是状态机:当你在async块里使用.await时,Future会暂停执行,等待子任务完成;恢复时需要从暂停的位置继续,这依赖于Future内部保存的状态(比如局部变量、未完成的子任务等)。

有些Future的内部状态会包含指向自身内部数据的指针(比如async块中捕获的变量,在暂停后需要准确找到这些变量的位置)。如果Future在内存中被移动(比如被转移到另一个栈帧或堆内存),这些内部指针就会指向无效的内存地址,导致内存不安全。

  • Unpin trait的作用是标记一个Future可以被安全移动——实现这个trait的Future,内部不会持有指向自身的指针,移动后不会破坏状态。
  • 默认情况下,async函数生成的Future(由GenFuture包装)不会自动实现Unpin,因为编译器无法保证它内部没有这类自引用指针。

当你尝试.await一个&mut Fut类型的引用时,编译器需要确保这个Future不会被移动:如果Fut没有实现Unpin,就必须通过Pin操作把它固定在内存的某个位置,禁止后续移动。这样,即使通过引用去await,Future的状态机位置不会改变,内部的指针始终有效,就能安全地恢复执行。

内容的提问来源于stack exchange,提问作者David Lichmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 15:45:15