简体   繁体   中英

Why does the compiler need that trait hint?

I had this code:

pub trait MiddlewareHandler: Clone + Send {
    //...probably unimportant for the question
}

#[deriving(Clone)]
pub struct Middleware {
    handlers: Vec<Box<MiddlewareHandler>>
}

#[deriving(Clone)]
pub struct Server{
    middleware: Middleware
}

This left me with the compiler yelling at me with:

src/server.rs:20:31: 20:37 error: the type `server::Server', which does not fulfill `Send`, cannot implement this trait
src/server.rs:20 impl http::server::Server for Server {
                                           ^~~~~~
src/server.rs:20:31: 20:37 note: types implementing this trait must fulfill `Send+Sized`
src/server.rs:20 impl http::server::Server for Server {

It took me ages to figure out I had to change Vec<Box<MiddlewareHandler>> to Vec<Box<MiddlewareHandler + Send>> so that the final code looks like this:

pub trait MiddlewareHandler: Clone + Send {
    //...probably unimportant for the question
}

#[deriving(Clone)]
pub struct Middleware {
    handlers: Vec<Box<MiddlewareHandler + Send>>
}

#[deriving(Clone)]
pub struct Server{
    middleware: Middleware
}

The code compiles now but I quite don't understand what exactly was the problem here. Why +Send in the Vec definition? I mean, the MiddlewareHandler trait does already implement Send + Clone . It looks rather superfluous to me.

Can someone share his wisdom with me why I had to change the code like that?

Seems like a bug, I filed #15155 .


The "problem" is the Send restriction on the http::server::Server . The definition is

pub trait Server: Send + Clone {

meaning the implementee needs to be both Clone (which is satisfied because you have implemented Clone via #[deriving(Clone)] ) and Send . The compiler automatically implements Send for types where the contents satisfies Send (this detail will be changing with opt-in built-in traits : they will require explicit implementations too), unfortunately the original type is something like

pub struct Middleware {
    handlers: Vec<Box<Trait>>
}

which does not implement Send in general: there's no way for the compiler to know that the erased type in the Box<Trait> is Send able, eg it could contain an Rc , and so be unsafe to transfer into a different task.

The compiler needs to know more information, that is, it needs to have a guarantee that the internal type is Send , which can be provided by adding more bounds to the trait object: Box<Trait + Send> ...

However, in this case, the MiddlewareHandler trait already has this Send bound as a supertrait (meaning the contents of the trait object have to satisfy Send already), so it's weird that the compiler isn't working out that Box<MiddlewareHandler> is Send (hence filing the bug).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM