Reputation: 743
I would like to print T
if Ok(T)
or a generic message and do this as part of the same println!()
statement.
My Current solution which works is:
fn main() {
let x: std::io::Result<i32> = Ok(54);
println!("hello {} ", x.map(|i| i.to_string()).unwrap_or("Bad".to_string()));
}
Is there a simpler and more efficient way that would leverage the Display
trait instead of needing to convert to string inside map
and unwrap_or
?
Upvotes: 0
Views: 246
Reputation: 665
While the accepted solution works and answers your question exactly, I don't think it's the most readable (or performant). (Correction: it's in fact faster.) A trait object feels like overkill to me. Consider using the same approach as yours, but instead, merge the map()
and unwrap_or()
into map_or()
(or map_or_else()
, to avoid an unnecessary heap allocation).
use std::io;
fn main() {
let x: io::Result<i32> = Ok(54);
println!("Hello, {}.", x.map_or_else(|_err| "Bad".into(), |i| i.to_string()));
}
Run this snippet on Rust Playground.
If you're not going to use the error value, you can make the code a touch more concise by renaming _err
to _
.
On the other hand, if you're going to be doing this often and in many places, you can create a wrapper type and implement your Display
logic for that.
use std::fmt::{self, Display};
use std::io;
fn main() {
let x: io::Result<i32> = Ok(54);
println!("Hello, {}.", PrintableResult(&x));
}
struct PrintableResult<'a, T: Display, E>(&'a Result<T, E>);
impl<'a, T: Display, E> Display for PrintableResult<'a, T, E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
self.0
.as_ref()
.map_or_else(|_| "Bad".into(), |val| val.to_string())
)
}
}
Run this snippet on Rust Playground.
If you don't mind PrintableResult
taking ownership of your Result
value, you can drop the borrow and the lifetime specifier with it.
If you'd like, you can also implement a to_printable()
extension method for Result
(via a trait).
// ...
fn main() {
let x: io::Result<i32> = Ok(54);
println!("Hello, {}.", x.to_printable());
let y: Result<i32, &'static str> = Err("Something went wrong.");
println!("Hello, {}.", y.to_printable());
}
// ...
trait ToPrintable<T: Display, E> {
fn to_printable(&self) -> PrintableResult<T, E>;
}
impl<T: Display, E> ToPrintable<T, E> for Result<T, E> {
fn to_printable(&self) -> PrintableResult<T, E> {
PrintableResult(&self)
}
}
Run this snippet on Rust Playground.
Upvotes: 0
Reputation: 3424
You can cast each of the Result
values as &dyn Display
let display = match &x {
Ok(i) => i as &dyn Display,
Err(_) => &"error" as &dyn Display,
};
// or with map
let display = x
.as_ref()
.map(|x| x as &dyn Display)
.unwrap_or_else(|_| &"error" as &dyn Display);
println!(
"hello {} ",
display
)
Both can be in-lined into the println!
, I have just separated them for readability.
Upvotes: 3