为何被固定(Pinned)的Future会实现Unpin trait?
为什么被固定的Future相关类型会实现Unpin?
首先明确几个核心概念:
- Unpin:标记 trait,表明类型可以安全移动——即使被 Pin 固定,移动也不会引发不安全行为。反之,
!Unpin类型是“不可移动”的,固定后移动会破坏内部自引用(比如异步块捕获自身引用的场景)。 - 异步块默认是!Unpin:Rust 编译器无法提前判断异步块生成的 Future 是否包含自引用,所以默认将其标记为
!Unpin,避免意外移动导致的问题。
一、为什么用 Box::pin 包装后,Pin<Box<Fut>> 会实现 Unpin?
这是因为:
Box<T>本身是指针类型,移动Box<T>只会移动栈上的指针,堆上的T位置完全不变——所以不管T是否为Unpin,Box<T>始终实现Unpin。- Rust 标准库对
Pin<P>的 Unpin 实现规则是:如果内部的P实现Unpin,那么Pin<P>自动实现Unpin。
结合这两点,Pin<Box<Fut>> 必然实现 Unpin——哪怕原 Future(比如你的异步块)是 !Unpin。此时移动 Pin<Box<Fut>> 只是移动指针,堆上的 Future 始终保持固定状态,不会破坏任何内部结构。
二、pin_mut! 的情况:Pin<&mut Fut> 不一定实现 Unpin
pin_mut! 生成的是 Pin<&mut Fut>,这种类型的 Unpin 实现依赖于原 Future:
- 如果原
Fut: Unpin,那么Pin<&mut Fut>也实现Unpin; - 如果原
Fut: !Unpin,那么Pin<&mut Fut>同样是!Unpin,无法直接传给你的test函数(因为test要求参数是Unpin)。
你问题里的表述存在一点偏差:只有 Pin<Box<Fut>> 这类基于指针容器的 Pin 类型,才会无视原 Future 的 Unpin 状态实现自己的 Unpin。
结合你的代码例子修改验证
如果把代码改成用 Box::pin 包装,就能通过编译:
fn test<T: Unpin>(t: T) {} fn main() { let b = async { 1 }; let pinned_b = Box::pin(b); test(pinned_b); // 编译通过,因为 Pin<Box<impl Future>> 实现了 Unpin }
而如果用 pin_mut!,依然会报错:
use std::pin::pin_mut; fn test<T: Unpin>(t: T) {} fn main() { let b = async { 1 }; pin_mut!(b); test(b); // 依然报错:`[async block]` 未实现 Unpin,因此 Pin<&mut [async block]> 也未实现 Unpin }
内容的提问来源于stack exchange,提问作者BugMaker
相关产品推荐
相关产品推荐

