Search code examples
genericsrusttraitsdynamic-dispatchtrait-objects

The trait cannot be made into an object


I have the following code:

extern crate futures; // 0.1.24

use futures::Future;
use std::io;

struct Context;

pub trait MyTrait {
    fn receive(context: Context) -> Future<Item = (), Error = io::Error>;
}

pub struct MyStruct {
    my_trait: MyTrait,
}

When I try to compile it I get the error message:

error[E0038]: the trait `MyTrait` cannot be made into an object
  --> src/lib.rs:13:5
   |
13 |     my_trait: MyTrait,
   |     ^^^^^^^^^^^^^^^^^ the trait `MyTrait` cannot be made into an object
   |
   = note: method `receive` has no receiver

I think I know why it happens, but how do I refer to the trait from the struct? Is it possible? Maybe there are other ways to implement the same behavior?


Solution

  • You can either add a type parameter to your struct, as in Zernike's answer, or use a trait object.

    Using the type parameter is better for performance because each value of T will create a specialized copy of the struct, which allows for static dispatch. A trait object uses dynamic dispatch so it lets you swap the concrete type at runtime.

    The trait object approach looks like this:

    pub struct MyStruct<'a> {
        my_trait: &'a dyn MyTrait,
    }
    

    Or this:

    pub struct MyStruct {
        my_trait: Box<dyn MyTrait>,
    }
    

    However, in your case, MyStruct cannot be made into an object because receive is a static method. You'd need to change it to take &self or &mut self as its first argument for this to work. There are also other restrictions.