Pin 常被说成「难懂」。这篇不讲抽象定义,而是先让一个自引用结构体真的被移动成悬空指针,再验证 Pin
编译:成功
运行(退出码 0):
创建后:data 在 0x16b3426e8,ptr 指向 0x16b3426e8,二者相同: true
移动后:data 在 0x16b342788,ptr 仍指向 0x16b3426e8,二者相同: false自引用的 Future 来自 async 状态机,见async/await 状态机。
编译:成功
运行(退出码 0):
Pin<Box<Data>> 被移动了两次,Data 的地址不变: true 源码:
1 | use std::{pin::Pin, marker::PhantomPinned};
2 | struct NoMove { v: u32, _p: PhantomPinned }
3 | fn main() {
4 | let mut p = Box::pin(NoMove { v: 1, _p: PhantomPinned });
5 | let r: &mut NoMove = p.as_mut().get_mut();
6 | r.v = 2;
7 | }
编译:失败
warning: unused import: `pin::Pin`
--> <实验目录>/src/u106c.rs:1:11
|
1 | use std::{pin::Pin, marker::PhantomPinned};
| ^^^^^^^^
|
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
error[E0277]: `PhantomPinned` cannot be unpinned
--> <实验目录>/src/u106c.rs:5:37
|
5 | let r: &mut NoMove = p.as_mut().get_mut();
| ^^^^^^^ within `NoMove`, the trait `Unpin` is not implemented for `PhantomPinned`
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required because it appears within the type `NoMove`
--> <实验目录>/src/u106c.rs:2:8
|
2 | struct NoMove { v: u32, _p: PhantomPinned }
| ^^^^^^
note: required by a bound in `Pin::<&'a mut T>::get_mut`
--> <rust 标准库源码>/library/core/src/pin.rs:1598:12
|
1596 | pub const fn get_mut(self) -> &'a mut T
| ------- required by a bound in this associated function
1597 | where
1598 | T: Unpin,
| ^^^^^ required by this bound in `Pin::<&mut T>::get_mut`
…(共 33 行)
源码:
1 | use std::{pin::Pin, marker::PhantomPinned};
2 | struct NoMove { v: u32, _p: PhantomPinned }
3 | fn main() { let x = NoMove { v: 1, _p: PhantomPinned }; let p = Pin::new(&x); let _ = p; }
编译:失败
error[E0277]: `PhantomPinned` cannot be unpinned
--> <实验目录>/src/u106d.rs:3:74
|
3 | fn main() { let x = NoMove { v: 1, _p: PhantomPinned }; let p = Pin::new(&x); let _ = p; }
| -------- ^^ within `NoMove`, the trait `Unpin` is not implemented for `PhantomPinned`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required because it appears within the type `NoMove`
--> <实验目录>/src/u106d.rs:2:8
|
2 | struct NoMove { v: u32, _p: PhantomPinned }
| ^^^^^^
note: required by a bound in `Pin::<Ptr>::new`
--> <rust 标准库源码>/library/core/src/pin.rs:1159:25
|
1159 | impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> {
| ^^^^^ required by this bound in `Pin::<Ptr>::new`
...
1181 | pub const fn new(pointer: Ptr) -> Pin<Ptr> {
| --- required by a bound in this associated function
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.i32 Unpin: ✓ String Unpin: ✓ Vec<u8> Unpin: ✓ Box<T> Unpin: ✓ &mut i32 Unpin: ✓ PhantomPinned Unpin: ✗ 含 PhantomPinned 的 struct Unpin: ✗ async fn 的 Future(跨 await 借用) Unpin: ✗ async 块(无借用) Unpin: ✗
编译:成功;警告:
warning: unused import: `Poll`
--> <实验目录>/src/u106f.rs:1:53
|
1 | use std::{pin::pin, future::Future, task::{Context, Poll, Waker}};
| ^^^^
|
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emitted
运行(退出码 0):
poll 栈上固定的 Future: Ready(6)
编译:成功
运行(退出码 0):
xPin 在 poll 里的使用见自定义 Future。