Grouping structures with enumerations

In Rust, how should related structures be grouped so that the function signature can accept several different types, referring to a specific type inside the method body?

The following example is for simplicity:

enum Command { Increment {quantity: u32}, Decrement {quantity: u32}, } fn process_command(command: Command) { match command { Command::Increment => increase(command), Command::Decrement => decrease(command), }; } fn increase(increment: Command::Increment) { println!("Increasing by: {}.", increment.quantity); } fn decrease(decrement: Command::Decrement) { println!("Decreasing by: {}.", decrement.quantity); } fn main() { let input = "Add"; let quantity = 4; let command: Command = match input { "Add" => Command::Increment { quantity: quantity }, "Subtract" => Command::Decrement { quantity: quantity }, _ => unreachable!(), }; process_command(command); } 

Compiling results in the following two errors:

 src/main.rs:13:24: 13:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 5 }, true) [E0248] src/main.rs:13 fn increase(increment: Command::Increment) { ^~~~~~~~~~~~~~~~~~ src/main.rs:17:24: 17:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 8 }, true) [E0248] src/main.rs:17 fn decrease(decrement: Command::Decrement) { ^~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors 

If I declare the structures separately and wrap the structures inside the struct tuples (correct terminology?) Each within the enum, then I get the expected result, but with verbosity and similar type names everywhere, I suspect that I misunderstood:

 struct Increment { quantity: u32, } struct Decrement { quantity: u32, } enum Command { Increment(Increment), Decrement(Decrement), } fn process_command(command: Command) { match command { Command::Increment(increment) => increase(increment), Command::Decrement(decrement) => decrease(decrement), }; } fn increase(increment: Increment) { println!("Increasing by: {}.", increment.quantity); } fn decrease(decrement: Decrement) { println!("Decreasing by: {}.", decrement.quantity); } fn main() { let input = "Add"; let quantity = 4; let command: Command = match input { "Add" => Command::Increment(Increment { quantity: quantity }), "Subtract" => Command::Decrement(Decrement { quantity: quantity }), _ => unreachable!(), }; process_command(command); } 

Output Launch:

 Increasing by: 4. 

Is packaging the structure as an enumeration (terminology?) Sharing the same name really the best solution? Command::Increment(Increment { quantity: 7 })

+5
source share
3 answers

Yes, this is the best you will get on this line of implementation. Enumeration is only one type; its options are just what options are, not types.

Another alternative is to use traits and generics:

 struct Increment { quantity: u32, } struct Decrement { quantity: u32, } trait Command { fn process(self); } impl Command for Increment { fn process(self) { println!("Increasing by {}", self.quantity); } } impl Command for Decrement { fn process(self) { println!("Decreasing by {}", self.quantity); } } 

Of course, this is not a direct parallel; if you want to save the command potentially different types, you will need to modify the process to take self: Box<Self> or &self , and you will need to work with Box<Command> or &Command , but in a different way doing things that may suit your requirements. As for definitions, itโ€™s cleaner.

+5
source

How about this, I'm not sure that I really understood your problem.

 enum Command { Increment (u32), Decrement (u32), } fn process_command(command: Command) { match command { Command::Increment(quantity) => increase(quantity), Command::Decrement(quantity) => decrease(quantity), }; } fn increase(quantity: u32) { println!("Increasing by: {}.", quantity); } fn decrease(quantity: u32) { println!("Decreasing by: {}.", quantity); } fn main() { let input = "Add"; let quantity = 4; let command: Command = match input { "Add" => Command::Increment (quantity), "Subtract" => Command::Decrement (quantity), _ => unreachable!(), }; process_command(command); } 
+3
source

Perhaps I misunderstand your simple example, but remember that you can directly apply methods for enumerations:

 enum Command { Increment {quantity: u32}, Decrement {quantity: u32}, } impl Command { fn process(self) { match self { Command::Increment { quantity } => { println!("Increasing by: {}.", quantity) }, Command::Decrement { quantity } => { println!("Decreasing by: {}.", quantity) }, }; } } fn main() { let input = "Add"; let quantity = 4; let command: Command = match input { "Add" => Command::Increment { quantity: quantity }, "Subtract" => Command::Decrement { quantity: quantity }, _ => unreachable!(), }; command.process(); } 

I like this version because it eliminates the redundancy of process_command(command) .

+1
source

Source: https://habr.com/ru/post/1215485/


All Articles