Ukonn Ra
Ukonn Ra

Reputation: 754

In Rust, how to make an vec of trait with self?

Just wondering how to put a trait with self into a vec? I thought it should be a common question but I have never searched the answer...

Here is the code:

use tokio::time::{delay_for, Duration};

#[async_trait::async_trait]
trait Interface: Default + Sized {
    async fn update(&mut self) -> bool where Self: Sized;
}

struct Adder {
    pub state: i32,
}

impl Default for Adder {
    fn default() -> Self {
        Self { state: 0 }
    }
}

#[async_trait::async_trait]
impl Interface for Adder {
    async fn update(&mut self) -> bool {
        delay_for(Duration::from_millis(100)).await;
        self.state = self.state + 1;
        println!("Inc state to: {}", self.state);
        return true;
    }
}

struct Suber {
    pub state: i32,
}


impl Default for Suber {
    fn default() -> Self {
        Self { state: 0 }
    }
}


#[async_trait::async_trait]
impl Interface for Suber {
    async fn update(&mut self) -> bool {
        delay_for(Duration::from_millis(100)).await;
        self.state = self.state - 1;
        println!("Dec state to: {}", self.state);
        return true;
    }
}

fn main() {
    let updaters: Vec<Box<dyn Interface>> = vec![Box::new(Adder::default()), Box::new(Suber::default())];
    for mut u in updaters {
        u.update();
    }
}

But I will get the error:

error[E0038]: the trait `Interface` cannot be made into an object
  --> src/main.rs:51:19
   |
4  | trait Interface: Default + Sized {
   |       ---------  -------   ----- ...because it requires `Self: Sized`
   |       |          |
   |       |          ...because it requires `Self: Sized`
   |       this trait cannot be made into an object...
...
51 |     let updaters: Vec<Box<dyn Interface>> = vec![Box::new(Adder::default()), Box::new(Suber::default())];
   |                   ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Interface` cannot be made into an object

Upvotes: 1

Views: 788

Answers (1)

QuarticCat
QuarticCat

Reputation: 1526

This error occurs because the trait Interface does not satisfy object safety.

  • It must not require Self: Sized
  • All associated functions must either have a where Self: Sized bound, or
    • Not have any type parameters (although lifetime parameters are allowed), and
    • Be a method that does not use Self except in the type of the receiver.
  • It must not have any associated constants.
  • All supertraits must also be object safe.

Update

You can change trait Interface: Default + Sized into trait Interface (because Default also requires Sized). But I don't know if that meets your need. @UkonnRa

Upvotes: 2

Related Questions