rust 异步移动{}的魔力是什么?

g6baxovj  于 2023-03-08  发布在  其他
关注(0)|答案(1)|浏览(93)

我和时雄一起工作,我花了一整天的时间试图创建一个未来的向量。
我总是和借位检查员打起来,直到最后有人建议使用async move {}技巧。
我不明白为什么这个方法有效(不像天真的方法)。
有人能帮我弄明白吗?

use futures::future;

async fn kill(processes: Vec<tokio::process::Child>) {
    let mut deaths = Vec::new();

    for mut p in processes {
        // following works
        deaths.push(async move { p.kill().await });

        // naive approach would trigger error:
        // deaths.push(p.kill());
        // "borrowed value does not live long enough"
    }
    
    future::join_all(deaths).await;
}
kwvwclae

kwvwclae1#

每次编写async { ... }时,Rust编译器都会为状态机生成代码,我们称之为任务。在示例中,任务被收集到一个向量中,但实际上只有在循环完成后才执行。
简单地说,Rust生成的任务看起来像这样:

struct Task1<'a> {
    p: &'a tokio::process::Child,
}

impl Future for Task1 { ... }

如果没有move关键字,这些任务会保留preferencesp只存在于循环的一次迭代中,但是任务在循环之后运行,所以这个引用是无效的-如果Rust允许您使用它,它将是一个悬空指针,触发Undefined Behavior。
写入move async意味着生成的任务已经取得了p的所有权。它不再是一个引用,值是任务的一部分:

struct Task1 {
    p: tokio::process::Child,
}

impl Future for Task1 { ... }

相关问题