calben
calben

Reputation: 1358

References to captured variables in an Actix server causes "argument requires that it must outlive 'static"

In the below example, I have parameters verbose and data_source that are set by command line parameters. verbose is a boolean flag, but data_source is used to select a default from a set of available functions that can be used depending on the data source for the application.

Actix uses a closure to set up a server, so I need to get these parameters into the closure. I added move for the bool, but I'm having trouble passing in the function to be used for the index and am getting lifetime errors. I've tried boxing the function, but that doesn't seem to help.

If I'm understanding the error message correctly, it's actually the closure itself that is failing to outlive 'static.

What should I do to solve this issue?

extern crate actix;
extern crate actix_web;
extern crate env_logger;

use actix_web::http::Method;
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};

enum DataSource {
    Postgres,
    HDF5,
}

fn index_postgres(req: &HttpRequest) -> HttpResponse {
    HttpResponse::Ok().body("not implemented")
}

fn index_hdf5(req: &HttpRequest) -> HttpResponse {
    HttpResponse::Ok().body("not implemented")
}

fn main() {
    let mut verbose = false;
    verbose = true;
    let mut data_source = DataSource::Postgres;
    data_source = DataSource::HDF5;

    let index = match data_source {
        DataSource::Postgres => index_postgres,
        DataSource::HDF5 => index_hdf5,
    };

    ::std::env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let sys = actix::System::new("test");

    server::new(move || {
        if verbose {
            App::new()
                .middleware(middleware::Logger::default())
                .resource("/", |r| r.method(Method::GET).f(index))
        } else {
            App::new().resource("/", |r| r.method(Method::GET).f(index))
        }
    })
    .bind("127.0.0.1:8080")
    .unwrap()
    .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
error: unsatisfied lifetime constraints
  --> src\main.rs:50:13
   |
48 |       server::new(move || {
   |                   ------- lifetime `'1` represents this closure's body
49 |           if verbose {
50 | /             App::new()
51 | |                 .middleware(middleware::Logger::default())
52 | |                 .resource("/", |r| r.method(Method::GET).f(index))
   | |__________________________________________________________________^ argument requires that `'1` must outlive `'static`
   |
   = note: closure implements `Fn`, so references to captured variables can't escape the closure

Upvotes: 1

Views: 382

Answers (1)

max taldykin
max taldykin

Reputation: 12908

I don't understand what compiler is trying to say but it obvious that you need move in handler closures:

if verbose {
    App::new()
        .middleware(middleware::Logger::default())
        .resource("/", move |r| r.method(Method::GET).f(index))
} else {
    App::new().resource("/", move |r| r.method(Method::GET).f(index))
}

This is because you need to move index from the outer closure.

Upvotes: 1

Related Questions