为何&i32在不同场景下有时实现Unpin trait有时却不实现?
Rust中Pin::new调用的编译差异问题解析
先看这段Rust代码:
use std::pin::Pin; fn main() { let val: i32 = 3; let val_pin = Pin::new(&val); f(val_pin); f(Pin::new(&val)); } fn f(_val: Pin<&dyn TestTrait>) {} trait TestTrait {} impl TestTrait for i32 {}
这段代码里,第6行let val_pin = Pin::new(&val);能正常编译,但第9行直接把Pin::new(&val)传给f却触发编译错误,错误信息如下:
error[E0277]: `dyn TestTrait` cannot be unpinned --> src/main.rs:9:7 | 9 | f(Pin::new(&val)); | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn TestTrait` | = note: consider using `Box::pin` note: required by a bound in `Pin::<P>::new` --> /usr/lib/rustlib/src/rust/library/core/src/pin.rs:482:23 | 482 | impl<P: Deref<Target: Unpin>> Pin<P> { | ^^^^^ required by this bound in `Pin::new`
原因解析
核心差异在于类型推导的时机和目标不同:
- 第6行:
Pin::new(&val)被赋值给val_pin时,Rust会推导val_pin的具体类型是Pin<&i32>。i32作为基础类型默认自动实现了Unpintrait,完全符合Pin::new要求的Target: Unpin约束,因此编译通过。后续把val_pin传给f时,只是将Pin<&i32>强制转换为Pin<&dyn TestTrait>(因为i32实现了TestTrait),这个转换是合法的。 - 第9行:直接调用
f(Pin::new(&val))时,Rust会根据f的参数类型Pin<&dyn TestTrait>反向推导Pin::new(&val)的类型。它会认为你要创建的是Pin<&dyn TestTrait>,此时Pin::new的Target类型是dyn TestTrait。但dyn TestTrait本身并没有实现Unpintrait(只有当trait本身标记了Unpin,或者所有实现该trait的类型都是Unpin时,dyn Trait才会自动实现Unpin,这里TestTrait没有标记Unpin),所以违反了Pin::new的约束,触发编译错误。
简单总结:前者先创建了针对具体类型i32的Pin,再转为 trait 对象;后者试图直接创建针对 trait 对象的Pin,而 trait 对象不满足Unpin要求。
内容的提问来源于stack exchange,提问作者user2623008
相关产品推荐
相关产品推荐

