Search code examples
rustobject-lifetime

How to fix: value may contain references; add `'static` bound to `T`


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


Solution

  • 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.