Moving a Value into a Fn Closure

I'm using actix-web at the latest alpha 1.0.0 release. My main looks like this:

fn main() {
    let config = Config::new();
    let config_clone = config.clone();

    HttpServer::new(move || App::new().configure(configure(config_clone)))
        .bind()
        .unwrap()
        .run();
}

My configure function:

pub fn configure(_config: Config) -> impl Fn(&mut RouterConfig) {
    move |mut _c| {
        ();
    }
}

The goal is that I want all of my actual application configuration for actix-web to live in one consolidated place, which is the goal of the App::configure method.

I get the following error:

error[E0507]: cannot move out of captured variable in an `Fn` closure
  --> src/main.rs:32:65
   |
30 |         let config_clone = config.clone();
   |             --------- captured outer variable
31 |
32 |         HttpServer::new(|| App::new().configure(configure(config_clone)))
   |                                                                 ^^^^^^^^^ cannot move out of captured variable in an `Fn` closure

How can I pass my Config value into the underlying closure? I need to do this because configuration will inform what happens inside of that closure.

You need to clone the config inside the closure:

fn main() {
    let config = Config::new();

    HttpServer::new(move || App::new().configure(configure(config.clone())))
        .bind()
        .unwrap()
        .run();
}
1 Like

Thank you, that was it!

It's kind of a hard thing, but is there any better, more ergonomic way to do this? I suppose I would probably have to look into Send to avoid the clones or wrap in an Arc.

I don't know actix that much, but looking at ::actix::App::configure the given closure does not require to have a : 'static bound on its borrows, so having

pub
fn configure (config: &'_ Config) -> impl Fn(&mut RouterConfig) + '_
{
    move |_c: &mut _| {
        mem::drop(config); // use config in the closure to ensure it is captured
    }
}

should allow you to:

fn main ()
{
    let config = Config::new();

    HttpServer::
        new(move || App::new().configure(configure(&config)))
            .bind()
            .unwrap()
            .run()
    ;
}

Arc is a typical solution for this. Actix launches one server per CPU thread, so there's a reason it wants it cloned (or thread-safely shared).

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.