0

I'm confused about how to use Rust's trait objects. I have a lot of vague partial-understandings but in the end I don't understand the error I'm getting.

I am trying to implement the Command Pattern in rust in order to move a cursor around a terminal. I have it set up to send trait objects that implement a Command trait, and have the Command trait generically typed. Can I not make this trait generic?

Here's an example-ified version of my code:

pub trait Command<T> {
    fn execute(&self, target_instance: &mut T);
}

pub trait Commandable<T> {
    fn send(&mut self, cmd: Box<impl Command<T>>);
}
//-------------------------------------------------------

struct Cursor {
    pos: (isize, isize),
}

impl Cursor {
    fn move_me(&mut self, direction: (isize, isize)) {
        self.pos.0 += direction.0;
        self.pos.1 += direction.1;
    }
}

impl Commandable<Cursor> for Cursor {
    fn send(&mut self, cmd: Box<impl Command<Cursor>>) {
        cmd.execute(self);
    }
}

struct MoveCommand {
    move_direction: (isize, isize),
}

impl MoveCommand {
    pub fn new(move_direction: (isize, isize)) -> Self {
        MoveCommand { move_direction }
    }
}

impl Command<Cursor> for MoveCommand {
    fn execute(&self, cursor: &mut Cursor) {
        cursor.move_me(self.move_direction);
    }
}
//------------------------------------------------------

fn handle_input(input: Option<&str>, target: &mut impl Commandable<Cursor>) {
    let mut cmd: Option<Box<dyn Command<Cursor>>> = None;
    if let Some(key) = input {
        match key {
            "K" => cmd = Some(Box::new(MoveCommand::new( (0, -1) ))),
            "J" => cmd = Some(Box::new(MoveCommand::new( (0, 1) ))),
            "H" => cmd = Some(Box::new(MoveCommand::new( (-1, 0) ))),
            "L" => cmd = Some(Box::new(MoveCommand::new( (1, 0) ))),
            _ => {}
        }
    }
    if let Some(boxed_cmd) = cmd {
        target.send(boxed_cmd); // <-----------------ERROR IS HERE
    }
}

fn main() {
    let mut cursor = Cursor { pos: (0, 0) };
    handle_input(Some("K"), &mut cursor);
}

Here's the error:

error[E0277]: the size for values of type `dyn Command<Cursor>` cannot be known at compilation time
  --> src/main.rs:54:21
   |
54 |         target.send(boxed_cmd);
   |                     ^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn Command<Cursor>`

1 Answers1

0

Answering my own question to help future folks:

My primary problem was that I didn't understand the difference between dyn MyTraitObj and impl MyTraitObj. I was using them interchangeably, so once I swapped all the impl's to dyn's, the code I posted compiled.

@LeoVen linked this, which solved that confusion for me: What is the difference between trait and impl trait when used as method arguments?

Thank you to all the folks that helped out.