What is the best practice to define enum-specific operations?

For example, I have lots of variants of Commands, all of them could be

  1. Parsed from &str
  2. Execute Commands
  3. use Display to show what they are doing.

I know that, we could just wrote 3 functions, parse, execute and display, and perform the logic in those functions.

But Since those commands have a strong inner-relationship (e.g., if I decided to change the parse behavior, the execute and display behavior might also be changed) and no matter what Command::MoveMouse is done, Command::Sleep won't be affected. Thus I want to seperate those functions into seperate files:

In short, I want:

impl Command::MoveMouse {
     fn parse(..)->..{..}
     fn execute(..)->..{..}
     fn display(..)->..{..}
}
impl Command::Sleep {
     fn parse(..)->..{..}
     fn execute(..)->..{..}
     fn display(..)->..{..}
}
...

rather than

impl Command {
    fn parse(..) -> .. {
        match command { Command::MoveMouse => .., Command:: }
    }
    fn execute(..) -> .. {
        match command { Command::MoveMouse => .., Command:: }
    }
    ...
}

What the best practice could be?


Should it be something like:

enum Command {
    MoveMouse(MoveMouse),
    Sleep(Sleep)
}
struct Sleep(i32);
impl Sleep {
    fn parse ()...
}
struct MoveMouse(i32);
impl MoveMouse {
    fn parse ()...
}

Your own suggestion is already good. It lets you pass the commands around as an enum when you don't need to know what's inside, and as a command struct once you have checked it and need to do command specific stuff. I would probably do it like that or use free functions, depending on their content and what I need to do.

Edit: to be clear, I mean this:

3 Likes

I like to point at IpAddr in std::net - Rust for this: make types for the individual things, then just stuff them all in an enum. Maybe there's then some common stuff you can define on the enum too, or maybe the reason it's best as an enum instead of a Box<dyn Foo> is that there really isn't much, and everything just matches on it.

2 Likes

If the operations have the same fn signature for each enum variant (parse, execute and display), you can define a trait for the operations, implement it for each variant's struct, and use enum_dispatch to call them. enum_dispatch implements the trait for the enum as a whole, and this implementation does the match for you.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.