为什么异步移动不移动这里的两个结构?

问题描述 投票:0回答:1

使用下面的代码我收到错误:

cargo build
   Compiling playground v0.1.0 (/home/explorer/playground)
error[E0507]: cannot move out of `config`, a captured variable in an `FnMut` closure
  --> src/main.rs:50:26
   |
36 |   pub fn execute_jobs(config: Arc<Config>) {
   |                       ------ captured outer variable
...
49 |               .with_run_async(Box::new(|_, _| {
   |                                        ------ captured by this `FnMut` closure
50 |                   Box::pin(async move {
   |  __________________________^
51 | |                     println!("run async every 2 seconds");
52 | |
53 | |                     do_job(&config.first, settings).await.unwrap();
   | |                             ------
   | |                             |
   | |                             variable moved due to use in coroutine
   | |                             move occurs because `config` has type `Arc<Config>`, which does not implement the `Copy` trait
54 | |                 })
   | |_________________^ `config` is moved here
For more information about this error, try `rustc --explain E0507`.

当然还有另一个

settings

我不明白为什么,因为我正在使用

async move
。我也无法理解这个错误。

代码“非常简单”(这里也是 REPL):


use std::{sync::Arc, time::Duration};
use tokio_cron_scheduler::{JobBuilder, JobScheduler};

struct Config {
    first: String,
    second: String,
}

struct Settings {
    first: String,
    second: String,
}

#[tokio::main]
async fn main() {
    let config = Config {
        first: "first".to_string(),
        second: "second".to_string(),
    };

    execute_jobs(Arc::new(config));

    // Simulate server in background
    tokio::time::sleep(Duration::from_secs(120)).await;
}

pub fn execute_jobs(config: Arc<Config>) {
    tokio::task::spawn(async move {
        let settings = Settings {
            first: "first".to_string(),
            second: "second".to_string(),
        };

        let scheduler = JobScheduler::new().await.unwrap();

        let job = JobBuilder::new()
            .with_cron_job_type()
            .with_schedule("*/2 * * * * *")
            .unwrap()
            .with_run_async(Box::new(|_, _| {
                Box::pin(async move {
                    println!("run async every 2 seconds");

                    do_job(&config.first, settings).await.unwrap();
                })
            }))
            .build()
            .unwrap();

        scheduler.add(job).await.unwrap();

        scheduler.start().await.unwrap();
    });
}

async fn do_job(first_config: &str, settings: Settings) -> Result<(), ()> {
    dbg!(first_config);

    dbg!(settings.second);

    Ok(())
}
rust async-await
1个回答
0
投票

问题可以简化为以下内容:

use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub fn execute_jobs(config: Arc<String>) -> Box<dyn FnMut() -> Pin<Box<dyn Future<Output = ()>>>> {
    Box::new(|| {
        Box::pin(async move {
            println!("run async every 2 seconds {config}");
        })
    })
}

问题是

with_run_async
需要一个
Box<dyn FnMut(Uuid, JobsSchedulerLocked) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>
类型的参数,所以你传递给它的闭包必须能够被多次调用(
FnMut
),但是你的闭包试图将
config
移动到它返回的
Future
,在第一次调用之后,将不再有
config
需要返回。您可以在将
config
传递到
async move
块之前克隆它:

use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub fn execute_jobs(config: Arc<String>) -> Box<dyn FnMut() -> Pin<Box<dyn Future<Output = ()>>>> {
    Box::new(|| {
        let config = Arc::clone(&config);
        Box::pin(async move {
            println!("run async every 2 seconds {config}");
        })
    })
}
© www.soinside.com 2019 - 2024. All rights reserved.