Home > Mobile >  pass variable to thread
pass variable to thread

Time:12-19

I'm searching a way to pass a variable url_path to this thread, as in this code:

async fn download_dist(all_paths: Vec<String>, mode: &str) {
    let mut download_path = "";
    let mut root_path = "";
    let mut url_path = String::new();

    if mode.contains("pool") {
        root_path = POOL_ROOT_PATH;
        url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
        download_path = DEBIAN_POOL_PATH;
    } else {
        root_path = DIST_ROOT_PATH;
        url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
        download_path = DEBIAN_DIST_PATH;
    }

    let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
        tokio::spawn(async move {
            println!("{}", url_path);
        })
    }))
    .buffer_unordered(10)
    .collect::<Vec<_>>();
    responses.await;
}

Error is : cannot move out of url_path, a captured variable in an FnMut closure move out of url_path occurs here

CodePudding user response:

.map calls the closure you provide many times.

The problem is that your url_path variable can only be moved to a thread once. So in order to move it to many threads (as you do), you have to clone it:

async fn download_dist(all_paths: Vec<String>, mode: &str) {
    let mut download_path = "";
    let mut root_path = "";
    let mut url_path = String::new();

    if mode.contains("pool") {
        root_path = POOL_ROOT_PATH;
        url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
        download_path = DEBIAN_POOL_PATH;
    } else {
        root_path = DIST_ROOT_PATH;
        url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
        download_path = DEBIAN_DIST_PATH;
    }

    let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
        let url_path = url_path.clone();
        tokio::spawn(async move {
            println!("{}", url_path);
        })
    }))
    .buffer_unordered(10)
    .collect::<Vec<_>>();
    responses.await;
}

Side note:

If you set a variable exactly once before using it and the compiler understands that, you can skip the initialization and the mut, like so:

async fn download_dist(all_paths: Vec<String>, mode: &str) {
    let download_path;
    let root_path;
    let url_path;

    if mode.contains("pool") {
        root_path = POOL_ROOT_PATH;
        url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
        download_path = DEBIAN_POOL_PATH;
    } else {
        root_path = DIST_ROOT_PATH;
        url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
        download_path = DEBIAN_DIST_PATH;
    }

    let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
        let url_path = url_path.clone();
        tokio::spawn(async move {
            println!("{}", url_path);
        })
    }))
    .buffer_unordered(10)
    .collect::<Vec<_>>();
    responses.await;
}

CodePudding user response:

You're using mut but you don't need to. Consider:

let (download_path, url_path, root_path) = if mode.contains("pool")
{
    (
        POOL_ROOT_PATH,
        format!("http://{}/{}",DEBIAN_REPOSITORY,DEBIAN_PATH),
        DEBIAN_POOL_PATH
    )
}
else
{
    (
        POOL_ROOT_PATH,
        format!("http://{}/{}/",DEBIAN_REPOSITORY,DEBIAN_DIST_PATH),
        DEBIAN_POOL_PATH
    )
};

Collapsing it like this exposes that you're not really changing either download_path or url_path anyway.

Tip: In Rust when you have let mut x = "" and then later assign to it, that's a sign you might want let x = if (...) { } instead.

If you're still stuck on the references, you can go down the Arc path:

  let url_path = Arc::new(url_path);

  let responses = futures::stream::iter(all_paths.into_iter().map(|path| {
        let url_path = url_path.clone();

        tokio::spawn(async move {
            println!("{}", url_path);
        })
    }))

This way each spawned task gets their "own" copy of the url_path, but to avoid needless copies, they're all Arc references to the same thing.

  • Related