# Result, Option and ?

> Rust has no null and no exceptions: absence is Option<T>, failure is Result<T, E>, and ? propagates both in one character.

Concept · Rust · https://levelcode.org/concepts/result-and-option

Rust encodes "might be missing" and "might fail" in types, so the compiler makes you handle them before you can use the value.

```rust
enum Option<T> { Some(T), None }
enum Result<T, E> { Ok(T), Err(E) }
```

An `Option<User>` isn't a `User`; you can't call its methods until you've dealt with `None`. That turns forgotten null checks into compile errors. A `Result` is `#[must_use]`, so ignoring one produces a warning.

## The ? operator

`?` unwraps `Ok`/`Some`, or returns early from the current function with the `Err`/`None`:

```rust
fn read_port(path: &str) -> Result<u16, Box<dyn std::error::Error>> {
    let text = std::fs::read_to_string(path)?;   // io::Error
    let port = text.trim().parse::<u16>()?;      // ParseIntError
    Ok(port)
}
```

On the way out it converts the error with `From::from`, which is how one function can propagate several error types into its own. It plays the role of Go's `if err != nil { return err }` — see [errors as values and wrapping](https://levelcode.org/concepts/error-wrapping) — in one character.

## Choosing error types

- **Libraries** return a typed error enum (often derived with `thiserror`) so callers can `match` on variants, exhaustively.
- **Applications** often collect errors into `anyhow::Error` and add context with `.context("loading config")` as they propagate.
- **Panics** (`unwrap`, `expect`, `panic!`) are for bugs and broken invariants, never for input a user or the network can control.

## Handy combinators

`map`, `and_then`, `unwrap_or`, `unwrap_or_else`, `ok_or` (Option → Result) and `ok()` (Result → Option) cover most transformations without a `match`. Collecting an iterator of `Result`s into `Result<Vec<_>, _>` stops at the first error.

The [error handling lesson](https://levelcode.org/roadmaps/rust/error-handling) builds custom error types and compares `thiserror` with `anyhow`.
