Why do I need 'static lifetime here and how to fix it?
I have taken off all extra irrelevant code to come to this clean one to reproduce the error I am getting:
trait EventsHandler{}
struct Engine{}
struct Request{}
struct RequestHandler<'a> {
r: &'a mut Request
}
impl<'a> EventsHandler for RequestHandler<'a>{}
impl Engine {
pub fn exec(&mut self, script: &str, handler: Box<dyn EventsHandler>){ }
}
pub fn handle_request(script: &str, r: &mut Request) {
let r_h:RequestHandler =RequestHandler {r};
let handler = Box::new(r_h);
let mut engine = Engine{};
engine.exec(script, handler);
}
and the error is:
error: explicit lifetime required in the type of `r`
label: lifetime `'static` required
The error is pointing to the parameter 'handler' in the last line of code.
As far as I can see everything seems live long enough. I can't see why there is a need for static and how I can go and fix that need or rewrite the code to avoid that requirement.
trait EventsHandler{}
struct Engine{}
pub struct Request{}
pub struct RequestHandler<'a> {
r: &'a mut Request
}
impl<'a> EventsHandler for RequestHandler<'a>{}
impl<'a> Engine {
pub fn exec(&'a mut self, script: &'a str, handler: Box<dyn EventsHandler + 'a>){ }
}
pub fn handle_request<'a>(script: &'a str, r: &'a mut Request){
let r_h:RequestHandler =RequestHandler {r};
let handler = Box::new(r_h);
let mut engine = Engine{};
engine.exec(script, handler);
}
I really don't know how to explain but this is what I did by following the tip in the error message. it can compile now.
Hope someone else can give a better explanation. :)
or you may take a look at: Box with a trait object requires static lifetime?
Though trait objects like dyn EventsHandler
erase the type at runtime, they still need to have information about the lifetime of the type so that it can be used in the type system. You can specify the lifetime explicitly with dyn EventsHandler + 'lifetime
, but it can also be elided, in which case Rust uses the following rule:
If the trait object is used as a type argument of a generic type then the containing type is first used to try to infer a bound.
- If there is a unique bound from the containing type then that is the default
- If there is more than one bound from the containing type then an explicit bound must be specified
If neither of those rules apply, then the bounds on the trait are used:
- If the trait is defined with a single lifetime bound then that bound is used.
- If
'static
is used for any lifetime bound then'static
is used.- If the trait has no lifetime bounds, then the lifetime is inferred in expressions and is 'static outside of expressions.
(Source: Lifetime elision, Rust reference)
In this case, the containing type Box<_>
has no lifetimes, the trait EventsHandler
has no lifetime bounds, and the type Box<dyn EventsHandler>
is used in a function signature (so outside of any expressions), so the lifetime is inferred as 'static
. In other words, Box<dyn EventsHandler>
, in this code, is equivalent to Box<dyn EventsHandler + 'static>
by the above rules, and can only contain values with a 'static
lifetime, which RequestHandler<'a>
is not.
If you want your Box<dyn EventsHandler>
to be able to contain values with a shorter lifetime than 'static
, you should add an explicit lifetime:
pub fn exec<'h>(&mut self, script: &str, handler: Box<dyn EventsHandler + 'h>)
// ^^^^ ^^^^^
// alternatively:
pub fn exec(&mut self, script: &str, handler: Box<dyn EventsHandler + '_>)
// ^^^^^
Following Rust's lifetime elision rules for trait objects, a Box<dyn Trait>
is in many cases shorthand for Box<dyn Trait + 'static>
. The meaning of the lifetime 'a
in Box<dyn Trait + 'a>
is that all lifetime parameters of the type implementing Trait
outlive 'a
(see the reference).
The 'static
can be relaxed by adding an explicit lifetime to the trait object. At minimum, this will entail an additional lifetime parameter on Engine::exec
:
impl Engine {
pub fn exec<'b>(&mut self, script: &str, handler: Box<dyn EventsHandler + 'b>){ }
}
See an amended code listing on the playground