Reputation: 91
I have a question for you, regarding my 'idx' structure and it's lifetimes... This structure is a cloneable multi threaded object.
This code works, how is it that moving 'idx' one layer up suddenly meant it didn't satify the 'static' lifetime requirement.
main() {
let w = webtask::Webtask::new();
// Wait for threads to finish
}
pub fn new() -> Self {
let (tx, rx) = oneshot::channel();
let mut idx = fastauth::createindex();
idx.load_index("users.dat.idx");
let lookup= warp::path!("lookup" / String).map(move |name| { Webtask::do_lookup(idx.clone(),name) });
let routes = lookup; //hello.or(lookup).or(check);
let (_addr, server) = warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async {
rx.await.ok();
});
let thread = tokio::task::spawn(server);
Webtask {thread,tx}
}
-------- However, when I try and move 'idx' to the outer layer function I get errors..
main() {
let mut idx = fastauth::createindex();
idx.load_index("users.dat.idx");
let w = webtask::Webtask::new(&idx);
// Here I plan to reuse 'idx' as it's really a global structure that will exist the entire time the program is running...
do_something_else(&idx);
// then wait for threads to finish...
exit_when_done();
}
...
pub fn new<'inf>(idx: &'inf fastauth::Idx) -> Self {
let (tx, rx) = oneshot::channel();
let lookup= warp::path!("lookup" / String).map(move |name| { Webtask::do_lookup(idx.clone(),name) }); // IS CAPTURED HERE
let routes = lookup; //hello.or(lookup).or(check);
let (_addr, server) = warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async { // IS REQUIRED TO LIVE AS LONG AS STATIC HERE.
rx.await.ok();
});
let thread = tokio::task::spawn(server);
// return our 'w' structure...
Webtask {thread,tx}
}
idx
has lifetime 'inf
but it needs to satisfy a 'static
lifetime requirement
Upvotes: 0
Views: 135
Reputation: 23463
The important lines in the working code are:
let mut idx = fastauth::createindex();
let lookup= warp::path!("lookup" / String).map(
move |name| { Webtask::do_lookup(idx.clone(),name) });
Here, idx
has type fastauth::Idx
and is moved inside the closure, so the compiler can guarantee that idx
will not be destroyed before the closure.
In the non-working code:
pub fn new<'inf>(idx: &'inf fastauth::Idx) -> Self {
let lookup= warp::path!("lookup" / String).map(
move |name| { Webtask::do_lookup(idx.clone(),name) });
Here, idx
has type &fastauth::Idx
so it is only a reference. That reference is moved inside the closure, but the real Idx
is still outside the closure (in the main
function), so the compiler can't guarantee that it won't get destroyed before the closure.
Depending on the reason why you wanted to move idx
up, you have several solutions:
new
can take idx
by value instead of taking it by referencepub fn new(idx: fastauth::Idx) -> Self {
but that means you won't be able to re-use idx
in main
after you call new
, so not really a solution for you.
Rc
or Arc
use std::sync::Arc;
main() {
let mut idx = Arc::new (fastauth::createindex());
idx.load_index("users.dat.idx");
let w = webtask::Webtask::new(idx.clone());
// Here I plan to reuse 'idx' as it's really a global structure that will exist the entire time the program is running...
do_something_else(idx);
// then wait for threads to finish...
exit_when_done();
}
pub fn new(idx: Arc::<fastauth::Idx>) -> Self {
let (tx, rx) = oneshot::channel();
let lookup= warp::path!("lookup" / String).map(move |name| { Webtask::do_lookup(idx.clone(),name) }); // IS CAPTURED HERE
let routes = lookup; //hello.or(lookup).or(check);
let (_addr, server) = warp::serve(routes)
.bind_with_graceful_shutdown(
([127, 0, 0, 1], 3030),
async { // IS REQUIRED TO LIVE AS LONG AS STATIC HERE.
rx.await.ok();
});
let thread = tokio::task::spawn(server);
// return our 'w' structure...
Webtask {thread,tx}
}
Rc
and Arc
allow multiple contexts to share ownership of a value, so that the value only gets destroyed when the last reference goes out of scope.
lazy_static
to create a global immutable static valueuse lazy_static;
lazy_static!{
static ref IDX: fastauth::Idx = {
let mut idx = fastauth::createindex();
idx.load_index("users.dat.idx");
idx
};
}
See the lazy_static
crate for details.
Upvotes: 3