Option Type Type Casting: A Paraphrased Understanding

Feedback

Question:

As a beginner in Rust coming from Python, I am unsure of the answer to what may seem like a basic question. Despite researching keywords like “Type Casting Option,” I have yet to find a satisfactory answer.

To inform the type checker of the return type in Python, we can utilize a specific logic that ensures a value will not be assigned to a variable of a different type. By implementing this logic after a certain line of code, the type checker will be aware of the proper return type.

from typing import Optional
def add_one(x: Optional[int] = None) -> int:
    if x is None:
        x = 0
    assert x is not None
    return x + 1
if __name__ == '__main__':
    add_one(0)    # 1
    add_one()     # 1
    add_one(999)  # 1000

Given that the interface remains constant in Rust, how can one ensure that the compiler recognizes that the type of

x

has changed from

Option

?

fn add_one(mut x: Option) -> i32 {
    if x == None {
        x = Some(0);
    }
    return x + 1;
}
fn main() {
    add_one(Some(0));
    add_one(None);
    add_one(Some(999));
}

Here’s the error message:

error[E0369]: binary operation `+` cannot be applied to type `std::option::Option`
 --> tmp.rs:5:14
  |
5 |     return x + 1;
  |            - ^ - {integer}
  |            |
  |            std::option::Option
  |
  = note: an implementation of `std::ops::Add` might be missing for `std::option::Option`

I attempted to include an additional i32 type variable (

let y: i32 = x;

) in my code, but it was unsuccessful as evidenced by the subsequent message.

error[E0308]: mismatched types
 --> tmp.rs:5:22
  |
5 |     let y: i32 = x;
  |                  ^ expected i32, found enum `std::option::Option`
  |
  = note: expected type `i32`
             found type `std::option::Option`



Solution 1:

Use

unwrap_or

:

fn add_one(x: Option) -> i32 {
    x.unwrap_or(0) + 1
}
fn main() {
    assert_eq!(1, add_one(Some(0)));
    assert_eq!(1, add_one(None));
    assert_eq!(1000, add_one(Some(999)));
}


Solution 2:

Specifically, how can the compiler be informed that the type of x is no longer an Option?


The compatibility of Rust’s type checker with dubious usage patterns can be avoided by redefining x as something other than an option.

fn add_one(mut x: Option) -> i32 {
    let x = if let Some(v) = x {
        v
    } else {
        0
    };
    return x + 1;
}

Alternatively, one could opt for a less sleek and productive approach (though it may be more similar to Python).

fn add_one(mut x: Option) -> i32 {
    let x = if x == None {
        0
    } else {
        x.unwrap()
    };
    return x + 1;
}

It’s important to remember that shadowing

x

is not necessary. Instead, you could opt to shadow

let y

which would result in a cleaner outcome.

Boiethios highlighted that Rust offers various tools for such scenarios, including the following utilities:

unwrap_or

,

map_or

, and so on.

Frequently Asked Questions