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

谁说胖子不能爱 提交于 2019-12-24 18:09:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!