I want to instantiate a variable that I will pass into a function that takes a T: Write
. It would be defined as follows:
let outputFile = match matches.opt_str("o") {
Some(fileName) => File::create(fileName).expect("could not open output file"),
None => std::io::stdout()
};
Currently, the compiler will complain about non-matching types in arms (File
vs. Stdout
). All I want is to declare outputFile
as something I can call any method from the Write
trait on and nothing else.
Does Rust allow me to do this or do I have to bring this entire match
expression as a parameter to be passed into that function?
If you want to return one of two (or more) separate types that implement a trait, then you need to return a trait object.
In this case you need the return value to own the object (since otherwise the File
would be destroyed before the end of the match
), so it it makes sense to use Box<dyn Write>
. Trait objects such as &Write
and Box<dyn Write>
are "fat" pointers, which include both a pointer to the struct (File
or Stdout
in this case) as well as a pointer to a vtable which describes how to implement Write
. Importantly, Box<dyn Write>
and &Write
automatically implement Write
.
Here's a working version (playground):
fn get_writer(f: Option<&str>) -> Box<dyn Write> {
match f {
Some(file_name) => Box::new(File::create(file_name).expect("could not open output file")),
None => Box::new(std::io::stdout()),
}
}
I've made a few changes from your code:
Added the Box<dyn Write>
return value (without a function you may need to have let outputFile: Box<dyn Write> = ...
; without having the type defined somewhere the compiler won't be able to infer that it needs to coerce the two types to the common Box<dyn Write>
. Once the compiler knows that it needs Box<dyn Write>
, it can coerce a Box<File>
to Box<dyn Write>
.
Boxed the two results.
Renamed fileName
to file_name
to match Rust conventions (and silence the warning).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With