# Navigating Safely with `Option` in Rust

Rust is SERIOUS about safety and control over memory. `Option` type – an essential tool in Rust's arsenal that keeps your code safe and sound. `Option` is a fundamental type in Rust and is widely used for error handling, optional values, and more. You would often encounter with functions in Rust that return `Option` type. It encourages the safe handling of potentially absent or invalid values and helps prevent dreaded null pointer errors that plague C++.

## **Introducing** Option

`Option` is an enumeration (enum) type that represents either a value or the absence of a value. It can either be "Some" or "None," helping you navigate the potentially missing or invalid values. It is defined by the standard library as follows:

```rust
enum Option<T> {
    Some(T),
    None,
}
```

The Option enum is so useful that it’s even included in the prelude. In other words, if a value has a type that isn’t an Option, you can safely assume that the value isn’t null.

### Option Variants

`The option` has two variants:

1. `Some(T)`: Represents a value of type `T`. &lt;T&gt; is a generic type parameter. It indicates that a value is present.
    
2. `None`: Represents the absence of a value.
    

Some and None are used directly without the Option:: prefix as they are included in the prelude as well.

## The Null-less Rust Coast

Rust is free of the "null" feature that many other languages have. Null is a value that means there is no value there. In languages with null, variables can always be in one of two states: null or not-null. The problem? If you try to treat null as not-null, you’ll get an error and since null or not-null is a common property, it's easier to fall into this.

## **Sailing with** `Option`

In Rust, `Option` is the ship, safeguarding you from these treacherous waters. Let's embark on this adventure with a simple example: Here the `fun1` function returns an `Option<f64>` which means it can either return `Some(f64)` or `None`.

```rust
fn fun1()->Option<f64>{
    let x = 0.0;
    if x ==0.0{
        return Some(x);
    }
    else{
        return None;
    }
}
fn main(){
    let x = fun1();
    let y = 1.0;
    let sum = x+y;
}

error[E0369]: cannot add `{float}` to `Option<{float}>`
 --> src/main.rs:4:16
  |
4 |     let sum = x+y;
  |               -^- {float}
  |               |
  |               Option<{float}>
```

The expression `x + y` tries to add an `Option<f64>` (`x`) to a `f64` (`y`). This is not allowed because Rust's type system enforces safety, and it doesn't allow adding an `Option` to a regular value directly. You would need to handle the `Option` using match statements or other methods to extract the value from `Some` (if it exists) and then perform the addition.

The `Option` has a large number of methods that are useful in a variety of situations like this. You can use methods like `unwrap` or `unwrap_or` to handle the `Option` and get its value.

### Methods to work with `Option`

The `Option` enum provides several methods and associated functions that allow you to work with optional values (values that can be either `Some(value)` or `None`). Here are some of the commonly used methods for `Option`:

1. `unwrap()`: This method extracts the value from a `Some` variant and panics if the variant is `None`. It should be used with caution, as it can lead to a panic.
    
2. `unwrap_or(default)`: Extracts the value from a `Some` variant or returns a default value if the variant is `None`. It provides a safer alternative to `unwrap()`.
    
3. `unwrap_or_else(fn)`: Similar to `unwrap_or`, it takes a closure that computes and returns the default value if needed. This allows for lazy evaluation of the default value.
    
4. `expect(msg)`: Similar to `unwrap()`, but it allows you to provide a custom error message that will be displayed if the variant is `None`.
    
5. `is_some()`: Returns `true` if the variant is `Some`, indicate the presence of a value.
    
6. `is_none()`: Returns `true` if the variant is `None`, indicating the absence of a value.
    
7. `map(fn)`: Applies a function to the inner value if it's `Some` and return a new `Option` containing the result. If it's `None`, it returns `None`.
    
8. `map_or(default, fn)`: Applies a function to the inner value if it's `Some`, return the result. If it's `None`, it returns the provided default value.
    

```rust
fn main(){
    let x = fun1();
    println!("{}",x.unwrap_or(10.0));
    println!("{}",x.unwrap_or_else(|| {fun2()}));
    println!("{}",x.expect(" It has None"));
    println!("{:?}",x.is_some());
}
fn fun2()->f64{
    100.0
}
fn fun1()->Option<f64>{
    let x = 0.0;
    if x ==0.0{
        return Some(x);
    }
    else{
        return None;
    }
}
----------------------------Output---------------------
0
0
0
true
```

### Pattern Matching with `Option`

```rust
fn main() {
    let x = fun1();
    match x {
        Some(x) => println!("The value is: {}", value),
        None => println!("No value found"),
    }
}
```

In the code above, we use `match` to extract and handle the value inside the `Option`. When `Some`, we print the value; when `None`, we indicate that no value was found.

### Another example of Deserialize and Serialize JSON

Let's see an example of JSON. You are working with JSON where a few attributes are optional. In the below example, let's assume style is optional, you could get JSON as input where style is absent.

```json
 {
"current_price": 100.0
"style":"American"
}
```

To handle this case, you could define struct as below:

```rust
#[derive(Clone,Debug,Deserialize,Serialize)]
pub struct Contract {
    pub current_price: f64,
    pub style: Option<String>
}
pub struct EquityOption {
    pub current_price: f64,
    pub style: Option<String>,
}
```

```rust
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Failed to read JSON file");
let data: utils::Contract = serde_json::from_str(&contents)
                           .expect("Failed to deserialize JSON")
let mut contract = EquityOption {
    current_price: data.current_price,
    style: Option::from(data.style.as_ref().unwrap_or(&default_style))

error[E0308]: mismatched types
style : Option::from(data.style.as_ref().unwrap_or(&"European".to_string()))
  |                 ^^^^^^^^^^^^^^^^^^^^^^ expected `Option<String>`, found `Option<&String>`
  |
  = note: expected enum `Option<String>`
             found enum `Option<&String>`
```

`Option::from` is used to convert a value of one type into an `Option` of that type.

We used `Option<String>` in our equity struct that is an `Option` that can either hold a `Some(String)` value. The `String` inside `Option<String>` is owned, meaning we have exclusive ownership of this String.

The above code gives an error because we get the `Option<&String>` type. `Option<&String>` is an `Option` that can hold a reference to a `String` (`&String`) or `None`. The `&String` inside `Option<&String>` is a borrowed reference, meaning it does not have ownership of the data, and it cannot be modified or moved. It points to an existing `String` owned elsewhere.

Either we can change the definition of our struct and use `Option<&String>` then we have to make sure about the borrowing and life of the referred string. Or we can clone the string as per our use case.

```rust
style : Option::from(String::from(data.style.as_ref()
        .unwrap_or(&"European".to_string())))
```

`.unwrap_or(&"European".to_string())` is used to provide a default value in case the `Option` is `None`. If the `data.style` is `Some(String)`, this part is ignored. If the `data.style` was `None`, it creates a new `String` with the value `"European"` and returns a reference to it. Note `unwrap_or` expect `&String` hence we return a reference `&` .

Here is youtube video discuss about the Option&lt;&T&gt; and &Option&lt;T&gt;

%[https://youtu.be/6c7pZYP_iIE?si=j4XuPseEopJ-RVey] 

## Conclusion

In conclusion, you typically use `Option` in Rust represents optional or nullable value and wants to avoid null pointer errors and ensure safer code. You most often use when:

* You expect a function to return a value but it might fail or return nothing, you use `Option` to handle the result.
    
* You have a variable that might be initialized with a valid value or remain uninitialized, you use `Option` to represent its state.
