ooo
ooo

Reputation: 743

How to display value contained in Result or a generic message if Result is Err

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

Answers (2)

verified_tinker
verified_tinker

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

pigeonhands
pigeonhands

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

Related Questions