跳到主要内容

pin

搜索

pin 

源代码
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 + Unpinselect! 和流操作符时,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 => {}
}