当我想将所有权传递给函数时,调用采用引用的异步 Rust 函数的惯用方法

Ben*_*con 4 rust

在编写异步 Rust 代码时,我经常遇到一种模式。假设我有一个Foo结构(在实际代码中,这可能类似于网络客户端)和一个异步函数,该函数引用该结构的实例:

struct Foo {
    i: i32
}

async fn use_foo(foo: &Foo) -> () {
    // do something with foo
}
Run Code Online (Sandbox Code Playgroud)

然后,我想use_foo同时运行几个,每个都有自己对不同Foo. 一种自然的(但不正确的)方法是:

use futures::stream::FuturesUnordered;

async fn foo_in_a_loop() {
    let futures = FuturesUnordered::new();
    for i in 0..10 {
        let foo = Foo { i };
        // does not compile: `foo` is dropped before the future is dropped
        futures.push(use_foo(&foo));
    }
}
Run Code Online (Sandbox Code Playgroud)

不能编译:

error[E0597]: `foo` does not live long enough
  --> src/main.rs:53:30
   |
53 |         futures.push(use_foo(&foo));
   |                              ^^^^ borrowed value does not live long enough
54 |     }
   |     - `foo` dropped here while still borrowed
55 | }
   | - borrow might be used here, when `futures` is dropped and runs the `Drop` code for type `FuturesUnordered`
   |
   = note: values in a scope are dropped in the opposite order they are defined

For more information about this error, try `rustc --explain E0597`
Run Code Online (Sandbox Code Playgroud)

我的问题归结为:修复此错误最惯用的方法是什么?我想“强制”use_foo取得该Foo实例的所有权。

现在,我正在使用一个拥有以下所有权的辅助函数foo

async fn use_foo_owned(foo: Foo) -> () {
    use_foo(&foo).await
}

async fn foo_in_a_loop_owned() {
    let futures = FuturesUnordered::new();
    for i in 0..10 {
        let foo = Foo { i };
        futures.push(use_foo_owned(foo));
    }
}
Run Code Online (Sandbox Code Playgroud)

它确实可以编译,但是仅仅为了取悦借用检查器而引入额外的函数是笨拙的。

请注意,有时use_foo可能来自另一个板条箱,我可能无法更改其签名,但如果有一个涉及修改的优雅解决方案use_foo,我也很感兴趣。

kmd*_*eko 9

使用一个async move {}块来创建一个拥有所有权foo并调用的 future use_foo

futures.push(async move { use_foo(&foo).await });
Run Code Online (Sandbox Code Playgroud)