What is an idiomatic way to deal with this match/Option situation?


#1
pub fn print_result(bcd: &BinaryCalculationData)
{
    let o1 = match bcd.operand_1
    {
        Some(v) => v,
        None => "None"
    };

    let o2 = match bcd.operand_2
    {
        Some(v) => v,
        None => "None"
    };

    let answer = match bcd.answer
    {
        Some(v) => v,
        None => "None"
    };


    println!("{} {} {} = {}", o1, bcd.operation, o2, answer);
}

No dice because v is a i32 and I’m trying to potentially assign &str None as you can see. You can see what I’m trying to do though… I want to “unwrap” these Options so I can print them.


#2

You can print the Option directly with {:?} instead of {}. This will call the Debug version of print.


#3

The question is how do you want to handle optional values that have None?

The idiomatic way to write print_result is to return an Option and use the ? operator to bail early when any optional value cannot be unwrapped: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=eaed5467dc4aad7df0ca07578cfab311

Alternatively, if you actually want to continue executing the function body (don’t bail early), you can use something like Option::map and Option::unwrap_or to transform the i32 to a String: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=409435536844027da5205588038705b9


#4

You’d actually want to use unwrap_or_else(|| "None".to_owned()) in this situation because unwrap_or will eagerly evaluate the string-allocating code, whereas unwrap_or_else won’t.


#5

I like solution #1 you gave here in this case.

I’m glad that you identified this because I had the impression that I should avoid working with Ok(()) for semantic reasons but actually, this allows us to display errors in the opposite case using ?.

For anyone else who reads this, I also just stumbled upon this article which is obviously a couple years old, but still a bit helpful.


#6

You’re absolutely right! Thanks for the reminder.


#7

Within limited scope that also works:

let by_ref = owned.as_ref().unwrap_or("None");

#8

This is brilliant. Thank you.