Search code examples
rustrust-tokioreqwest

How to resolve the 'Vec<[async block@src/main.rs:24:13: 24:56]>' error in Rust asynchronous programming?


I want to use reqwest with Tokio to send asynchronous requests, but the compiler keeps telling me there's a 'Vec<[async block@src/main.rs:24:13: 24:56]>' error. The code is as follows.

async fn async_req(
    url: &str,
    client: reqwest::Client,
) -> Result<reqwest::Response, reqwest::Error> {
    let response = client
        .get(url)
        .timeout(std::time::Duration::from_secs(180))
        .send()
        .await?;

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let urls = vec!["http://localhost:5000/hello", "http://localhost:5000/world"];

    let mut handles = vec![];

    let client = reqwest::Client::new();
    for url in urls {
        let handle = {
            let client = client.clone();
            async move { async_req(url, client).await }
        };
        handles.push(handle);
    }
    let (r1, r2) = tokio::join!(handles[0], handles[1]);

    Ok(())
}

/*
output: 
 src/main.rs:28:33
   |
28 |     let (r1, r2) = tokio::join!(handles[0], handles[1]);
   |                                 ^^^^^^^^^^ move occurs because value has type `[async block@src/main.rs:24:13: 24:56]`, which does not implement the `Copy` trait
*/

I have tried using ChatGPT and searching from Stack Overflow to find a solution, but I have not yet found a solution. The configuration of Cargo.toml is as follows, and the Rust compiler version I am using is 1.72.1 (d5c2e9c34, 2023-09-13)

[package]
name = "reqwest_tokio_demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
reqwest = { version = "^0.11" }
tokio = { version = "^1", features = [ "full" ] }

I would appreciate it if someone could help me clear up this confusion, and any reply are welcome. Thanks.


Solution

  • The full error message, which you only included part of in your question is this:

    error[E0507]: cannot move out of index of `Vec<[async block@src/main.rs:26:13: 26:56]>`
      --> src/main.rs:30:33
       |
    30 |     let (r1, r2) = tokio::join!(handles[0], handles[1]);
       |                                 ^^^^^^^^^^ move occurs because value has type `[async block@src/main.rs:26:13: 26:56]`, 
    which does not implement the `Copy` trait
    

    In general, futures can't be copied. But accessing handles[0] is trying to move the future out of the vector. Either it must copy it or else leave the vector in an invalid state. This is what the error is telling you.

    Why do you need the vector to be around after you've run the futures? I'm guessing you don't. In which case, don't keep it around. Remove the futures from it instead of trying to copy them:

    let h0 = handles.pop().unwrap();
    let h1 = handles.pop().unwrap();
    let (r1, r2) = tokio::join!(h0, h1);
    

    Those unwraps are ugly, but they are only there because your code is making an assumption that there are exactly 2 futures in the Vec. Instead you can use join_all to join on all of the futures, regardless of how many there are:

    use futures::future::join_all;
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let urls = vec!["http://localhost:5000/hello", "http://localhost:5000/world"];
    
        let mut futures = vec![];
        let client = reqwest::Client::new();
        for url in urls {
            let handle = {
                let client = client.clone();
                async move { async_req(url, client).await }
            };
            futures.push(handle);
        }
    
        let results = join_all(futures).await;
    
        Ok(())
    }
    

    And there are other ways to join multiple futures. e.g. see: