Polymorphism with mixed ownership (match of File vs stdout)

I'd love to make this code work:

    let arg = "-";
    match arg {
        "-" => std::io::stdout() // as &std::io::Write,
        path => File::create(&path).unwrap() // as &std::io::Write,
    }
    .write_all("blah".as_bytes()).unwrap();

Both arms of the match implement std::io::Write, but they're different types with different ownership, so I'm struggling to unify them to get a neat polymorphic .write_all() call. (I know I could duplicate the .write_all() call, but then it wouldn't be neat any more :slight_smile: )

You can't borrow them, since they are owned by their match arms, but you can box them: Rust Playground You can also avoid some indirection by putting them in an enum and implement Write for it. I think it has only two required methods.

You need to declare the storage beforehand if you want to borrow them:

use std::fs::File;
use std::io;

fn main() {
    let arg = "-";
    let mut file;
    let mut stdout;
    let output: &mut std::io::Write = match arg {
        "-" => {
            stdout = io::stdout();
            &mut stdout
        }
        path => {
            file = File::create(&path).unwrap();
            &mut file
        },
    };
    output.write_all("blah".as_bytes()).unwrap();
}
4 Likes

Got it. Thank you.