macro_rules! pin {
($($x:ident),*) => { ... };
($(
let $x:ident = $init:expr;
)*) => { ... };
}展开描述
在栈上钉住一个值。
调用 async fn 会返回匿名的 Future 值,这些值是 !Unpin 的。
这些值在被 poll 之前必须先固定。调用 .await 会
处理这一点,但会消费掉 future。如果需要在
&mut _ 引用上调用 .await,则由调用者负责固定该 future。
可以通过使用 Box::pin 进行分配,或者通过 pin!
宏使用栈来固定。
下面的代码无法编译:
ⓘ
async fn my_async_fn() {
// async logic here
}
#[tokio::main]
async fn main() {
let mut future = my_async_fn();
(&mut future).await;
}要让这段代码能够工作,需要进行固定:
use tokio::pin;
async fn my_async_fn() {
// async logic here
}
let future = my_async_fn();
pin!(future);
(&mut future).await;当使用 select! 以及需要 T: Stream + Unpin 的流操作符时,固定非常有用。
§Usage
pin! 宏接受标识符作为参数。它不能用于
表达式。
下面的代码无法编译,因为传给 pin! 的是一个表达式。
ⓘ
async fn my_async_fn() {
// async logic here
}
#[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() {
// async logic here
}
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);
}
}
}由于先赋值给变量再进行固定是常见操作,因此宏 也提供了一个变体,可以一步完成这两件事。
use tokio::{pin, select};
async fn my_async_fn() {
// async logic here
}
pin! {
let future1 = my_async_fn();
let future2 = my_async_fn();
}
select! {
_ = &mut future1 => {}
_ = &mut future2 => {}
}