macro_rules! pin {
($($x:ident),*) => { ... };
($(
let $x:ident = $init:expr;
)*) => { ... };
}展开描述
在栈上 pin 一个值。
对 async fn 的调用返回的是匿名的 Future 值,这些值是 !Unpin 的。必须先将这些值 pin 才能 poll。调用 .await 会处理这一点,但会消费 future。如果需要在 &mut _ 引用上调用 .await,则调用者负责 pin 该 future。
可以通过使用 Box::pin 分配来 pin,也可以使用 pin! 宏在栈上 pin。
下面的代码将无法编译:
ⓘ
async fn my_async_fn() {
// 这里是异步逻辑
}
#[tokio::main]
async fn main() {
let mut future = my_async_fn();
(&mut future).await;
}要使其工作,需要 pin:
use tokio::pin;
async fn my_async_fn() {
// 这里是异步逻辑
}
let future = my_async_fn();
pin!(future);
(&mut future).await;在使用需要 T: Stream + Unpin 的 select! 和流操作符时,pin 很有用。
§Usage
pin! 宏以标识符作为参数。它不能与表达式一起使用。
下面的代码无法编译,因为将表达式传递给了 pin!。
ⓘ
async fn my_async_fn() {
// 这里是异步逻辑
}
#[tokio::main]
async fn main() {
let mut future = pin!(my_async_fn());
(&mut future).await;
}§示例
与 select 一起使用:
use tokio::{pin, select};
use tokio_stream::{self as stream, StreamExt};
async fn my_async_fn() {
// 这里是异步逻辑
}
let mut stream = stream::iter(vec![1, 2, 3, 4]);
let future = my_async_fn();
pin!(future);
loop {
select! {
_ = &mut future => {
// Stop looping `future` will be polled after completion
break;
}
Some(val) = stream.next() => {
println!("got value = {}", val);
}
}
}由于先赋值给变量然后 pin 很常见,所以该宏还有一个变体,支持一次性完成这两个操作。
use tokio::{pin, select};
async fn my_async_fn() {
// 这里是异步逻辑
}
pin! {
let future1 = my_async_fn();
let future2 = my_async_fn();
}
select! {
_ = &mut future1 => {}
_ = &mut future2 => {}
}