Polymorphism and Map operations


I am an experienced java developer and new to Rust. Since I started learning Rust I try to write idiomatic Rust but the old habits of the past are still haunting me! :slight_smile:

In the following code snippet, I try to parse a cmd line argument parse and validate it as an existing directory and based on the results create a trait implementation and finally call its method. I use the match early return technique and method chaining. I have also thought to try polymorphism (just for learning) but it backfired. It took me a while to get the map_or_else closure returns to pass compilation. I guess the Box polymorphic return is excessive. I could use an if-else statement to avoid polymorphism. So is there a better way to write this logic? Thank you in advance for your input!

pub trait Printer {
fn print(&self, templates: &[Template], ctx: &Context) -> Result<(), String>;

pub struct ConsolePrinter {}

impl Printer for ConsolePrinter { ... }

pub struct FilePrinter {
   dir: PathBuf,

impl Printer for FilePrinter { ... }

fn main() {
  match args.first().map(|dir| PathBuf::from(dir)) {
    Some(path) => if !path.is_dir() {
        return Err(format!("Path is not a directory: {}", path.display()));
    } else if !path.exists() {
        return Err(format!("Directory doesn't exist: {}", path.display()));
    } else { Some(path) },
    None => None,
    || Box::new(ConsolePrinter::new()) as Box<dyn Printer>,
    |p| Box::new(FilePrinter::new(p)))
    .print(release.templates(), &context)

In Rust lightweight non-boxed alternative to polymorphism is enum:

enum Printer {

If you need "open" and run-time polymorphism, then Box is usually the right solution (that's essentially what Java does).

If you need runtime polymorphism inside a single scope, you can avoid boxing:

let file_printer;
let console_printer;
let chosen_printer: &dyn Printer;

if random() {
   file_printer = FilePrinter::new();
   chosen_printer = &file_printer;
} else {
   console_printer = ConsolePrinter::new();
   chosen_printer = &console_printer;

Thanks for the suggestions! I haven't thought of enum. It's very appropriate for this use case.

1 Like