问题
I managed yet again to run into a lifetime issue that I seem to be unable to solve on my own.
I have this trait
pub trait MiddlewareHandler: Clone {
fn invoke (&self, req: &Request, res: &mut Response) -> bool {
true
}
// we need this because otherwise clone() would be ambiguous
fn clone_box(&self) -> Box<MiddlewareHandler> {
box self.clone() as Box<MiddlewareHandler>
}
}
impl MiddlewareHandler for fn (req: &Request, res: &mut Response) -> bool {
fn invoke(&self, req: &Request, res: &mut Response) -> bool{
(*self).invoke(req, res)
}
}
impl Clone for Box<MiddlewareHandler> {
fn clone(&self) -> Box<MiddlewareHandler> {
self.clone_box()
}
}
That I implement for fn (req: &Request, res: &mut Response) -> bool
in order to be able to use accept lightweight functions and more heavy weight MiddlewareHandler
implementors at the same time.
I store them as Vec<Box<MiddlewareHandler>>
pub struct Middleware {
handlers: Vec<Box<MiddlewareHandler>>
}
Now, the problem is, the compiler is yelling at me right here:
pub fn add<T: MiddlewareHandler> (&mut self, handler: T) {
self.handlers.push(box handler);
}
It says:
error: value may contain references; add `'static` bound to `T`
self.handlers.push(box handler);
The implementation should be pretty similar to the one used here:
https://github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67
However, I seem to be unable to see the difference :-/
If anyone would like to give me a hand, I pushed the code to github into the static
branch:
https://github.com/floor-org/floor/tree/static
回答1:
The problem here is that, in order to safely create a boxed trait object, the original object cannot have any lifetime parameters (besides static
), or the object itself also needs to respect that lifetime, which isn't possible in general. To fix it:
pub fn add<T: MiddlewareHandler + 'static> (&mut self, handler: T) {
self.handlers.push(box handler);
}
Reads a bit weird, but it's saying "T
needs to implement MiddlewareHandler
and it cannot contain any references that do not have the static
lifetime". This only works for static
.
回答2:
A trait object erases the type of the internal data, meaning it is not known just by looking at the Box<Trait>
trait object. In particular, any lifetimes of the data is erased too, so the compiler cannot tell if/when a trait object contains references to invalid data (i.e. lifetime of some reference has expired), hence Rust currently enforces that any data in a owned trait object must never "expire". That is, there are no references in it (well, to be precise that any references are valid forever, i.e. 'static
).
This expressed via the built-in "trait" 'static
:
pub fn add<T: 'static + MiddlewareHandler>(...
(This may change in future, with owned trait objects able to be bounded by real lifetimes, and so storing non-'static
references would be safe.)
来源:https://stackoverflow.com/questions/24375771/how-to-fix-value-may-contain-references-add-static-bound-to-t