---
title: On Rust's Option and Result Enums
description: This article will discuss Rust's Option and Result enums, and ways to work with them without using match.
---

[KnowBe4 Engineering Blog | Software & Cloud Architecture Tips ](https://www.knowbe4.com/careers/blogs/engineering)

# [On Rust's Option and Result Enums](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums)

 Written by [Daniel Cormier](https://www.knowbe4.com/careers/blogs/engineering/author/daniel-cormier) | Jan 28, 2022 8:43:51 PM

This article will discuss Rust's `Option` and `Result` enums, and ways to work with them without using `match`. This came about because someone in our internal chat was lamenting how frequently they needed to use `match`. I found that I used `match` very frequently when Rust was newer to me, but now I use it much, much less.

Both of those enums have *many* methods that can often be used instead of `match`. I frequently refer back to the docs for [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html#implementations)/[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html#implementations) when I have an instance of one of those that I need to do something with. Specifically, I want to draw your attention to their methods that take an `FnOnce`. Let's go over some of those.

## [`.map()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#map)

The most common of these methods that I use is `.map()` (see [`Option::map()`](https://doc.rust-lang.org/std/option/enum.Option.html#method.map)/[`Result::map()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map)). It lets you inspect the inner `T` of an `Option<T>`/`Result<T, E>`, and optionally replace it, even with a different type.

Before we dive into this, a couple of thing notes:

- For clarity, I am going to use type annotations for all variables, even when they may not be needed.
- To try to make all the types involved more clear, I will often assign new variables rather than chain functions together.
- At the end of each section, there is a link to related code in the [Rust playground](https://play.rust-lang.org/) for you to explore further.

First, let's look at an example of how you could use `match` to convert an `Option<i32>` to `Option<String>`:

```
let before: Option<i32> = Some(-2);
let after: Option<String> = match before {
    Some(val) => Some(val.to_string()),
    None => None,
};

assert_eq!(Some(String::from("-2")), after);
```

Now let's look at `Option::map()`. For `Option`, if you call `.map()` and you have `Some`, it passes the inner value to your `FnOnce`, and whatever value you return becomes the value in the `Some`. If the value was `None`, then your `FnOnce` isn't called.

For example, let's again say you have `Option<i32>`and you need `Option<String>`. Here's how you can do that with `.map()`:

```
let before: Option<i32> = Some(-2);
let after: Option<String> = before.map(|i| i.to_string());

assert_eq!(Some(String::from("-2")), after);
```

If the value is `None`, then that `FnOnce` passed to `.map()` just isn't called, and you're still given an `Option<String>` (but the value is still `None`).

```
let before: Option<i32> = None;
let after: Option<String> = before.map(|i| i.to_string());

assert_eq!(None, after);
```

It works similarly for `Result`, just with `Ok` instead of `Some`, and `Err` instead of `None`.

This will convert `Result<i32, &str>` to `Result<String, &str>`:

```
let before: Result<i32, &str> = Ok(-2);
let after: Result<String, &str> = before.map(|i| i.to_string());

assert_eq!(Ok(String::from("-2")), after);
```

And it won't call your `FnOnce` if the value is `Err`.

```
let before: Result<i32, &str> = Err("there was an error");
let after: Result<String, &str> = before.map(|i| i.to_string());

assert_eq!(Err("there was an error"), after);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=75ad7e9f7cf650879ae76754a4fa2d95)

## [`.map_err()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#map_err)

Closely related to that is [`.map_err()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err). This one only exists on `Result`, but is *very* useful. This method works the same as [`.map()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map), but only gets called if the value is `Result::Err`, and lets you inspect/change the error value. This is useful if you need to change the type of the error, or even when you just want to trace/log an error if there is one. For example:

```
val.map_err(|err| {
    error!(error = %err, "Error doing it");

    err
})?;
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5209cf316ae82b2652a422b30a560597)

## [`.and_then()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#and_then)

Another one is `.and_then()` ([`Option::and_then()`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.and_then)/[`Result::and_then()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then)). If you call this and you have `Some`, it passes the inner value to your `FnOnce`, and instead of returning a new value to go *inside* `Some` (like what `.map()` does), you return an entire *replacement* `Option`. This means you can, for example, have `Some` and convert it to `None`.

Extending the original example of converting an `Option<i32>` into an `Option<String>`, but *only* if the value is greater than zero. Otherwise, `None`.

First, for `Option<i32>`:

```
let before: Option<i32> = Some(2);
let after: Option<String> = before.and_then(|i| {
    if i > 0 {
        Some(i.to_string())
    } else {
        None
    }
});

assert_eq!(Some(String::from("2")), after);
```

It works the same way for `Result<i32, &str>`, just with `Ok` instead of `Some`:

```
let after: Result<i32, &str> = Ok(2);
let before: Result<String, &str> = after.and_then(|i| {
    if i > 0 {
        Ok(i.to_string())
    } else {
        Err("value must be > 0")
    }
});

assert_eq!(Ok(String::from("2")), before);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2b531a077b2f9d3c5c66df155878dcad)

## [`.or_else()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#or_else)

You can use `.or_else()` ([`Option::or_else()`](https://doc.rust-lang.org/std/option/enum.Option.html#method.or_else)/[`Result::or_else()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.or_else)) to try something else if you don't have `Some`/`Ok`. The `FnOnce` passed to this method will be called for `None`/`Err`, and it must return the same type as the original `Option`/`Result`. You cannot use it to convert the inner type. It's useful, for example, if you have another way to try to get the needed value.

Continuing the examples with `Option<i32>`:

```
let before: Option<i32> = None;
let after: Option<i32> = before.or_else(|| Some(0));

assert_eq!(Some(0), after);
```

It's similar for `Result` (with the `FnOnce` getting called for `Err`), but you may change the type of `Err(E)` (like [`Result::map_err()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err)). You could use it to return an `Ok` value for some `Err` values, while returning or mapping other `Err` values.

```
let before: Result<i32, &str> = Err("a specific error");
let after: Result<i32, OtherError> = before.or_else(|err| {
    if err == "a specific error" {
        Ok(0)
    } else {
        Err(OtherError("mapped to another error"))
    }
});

assert_eq!(Err(OtherError("mapped to another error")), after);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f57be9f09e3f65f536d318d4e5064ff4)

## [`.ok_or_else()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#ok_or_else)

If you have an `Option` and need a `Result` (`Some` → `Ok`, `None` → `Err`), there's [`Option::ok_or_else()`](https://doc.rust-lang.org/std/option/enum.Option.html#method.ok_or_else).

```
let before: Option<i32> = Some(-2);
let after: Result<i32, &str> = before.ok_or_else(|| "no value");

assert_eq!(Ok(-2), after);
```

```
let before: Option<i32> = None;
let after: Result<i32, &str> = before.ok_or_else(|| "no value");

assert_eq!(Err("no value"), after);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=14953daa0bd684601de04dc56918d300)

## [`.ok()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#ok)

If you have a `Result` and need an `Option` (`Ok` → `Some`, `Err` → `None`), there's [`Result::ok()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.ok) method. It doesn't take an `FnOnce`, but it's nice to know about how to do the opposite of [`Option::ok_or_else()`](https://doc.rust-lang.org/std/option/enum.Option.html#method.ok_or_else).

```
let before: Result<i32, &str> = Ok(-2);
let after: Option<i32> = before.ok();

assert_eq!(Some(-2), after);
```

```
let before: Result<i32, &str> = Err("no value");
let after: Option<i32> = before.ok();

assert_eq!(None, after);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e5dd7599072f2dc4f0b27639011545a1)

## [`.flatten()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#flatten)

Sometimes chaining methods together can get you something like `Option<Option<T>>`, where you need `Option<T>`. The [`.flatten()` method](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.flatten) will remove one layer of nested `Option`.

```
let before: Option<Option<Option<i32>>> = Some(Some(Some(-2)));
let after: Option<Option<i32>> = before.flatten();

assert_eq!(Some(Some(-2)), after);

let last: Option<i32> = after.flatten();

assert_eq!(Some(-2), last);
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8e11ccce0e201fe43c2c63a1899a096b)

That there is an [experimental `Result::flatten()` method](https://doc.rust-lang.org/std/result/enum.Result.html#method.flatten), but it is still [under discussion](https://github.com/rust-lang/rust/issues/70142).

## [`.transpose()`](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#transpose)

Other times you'll end up with something like `Option<Result<T, E>>` when you need `Result<Option<T>, E>`. Guess what? There's a method for that: [`.transpose()`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose) is what you want.

And if you need to, you can use [`Result::transpose()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose) to go the other way, from `Result<Option<T>, E>` to `Option<Result<T, E>>`

```
let input: Option<&str> = Some("-2");
let mapped: Option<Result<i32, ParseIntError>> = input.map(str::parse);
let result: Result<Option<i32>, ParseIntError> = mapped.transpose();

assert_eq!(Ok(Some(-2)), result);

// Now that it's a `Result`, you could do normal error handling
// stuff, like use the `?` operator.

// And if you need to turn a `Result<Option<T>, E>` into an
// `Option<Result<T, E>>`, you can call `.transpose()` on _that_.
assert_eq!(Some(Ok(-2)), result.transpose());
```

```
let input: Option<&str> = Some("not an i32");
let mapped: Option<Result<i32, ParseIntError>> = input.map(str::parse);
let result: Result<Option<i32>, ParseIntError> = mapped.transpose();

assert_eq!(Err(ParseIntError{kind: IntErrorKind::InvalidDigit}), result);
assert_eq!(Some(Err(ParseIntError{kind: IntErrorKind::InvalidDigit})), result.transpose());
```

```
let input: Option<&str> = None;
let mapped: Option<Result<i32, ParseIntError>> = input.map(str::parse);
let result: Result<Option<i32>, ParseIntError> = mapped.transpose();

assert_eq!(Ok(None), result);
assert_eq!(None, result.transpose());
```

[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ba39890643fc5c36ab8b078032e58203)

## [TL; DR](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums?hs_amp=true#tldr)

If you have an `Option` or `Result` and you want to do something with the value inside, or convert it in some way, look at what methods are available. There's a good chance there's something that'll let you do what you're after without having to use `match`.

See the docs for [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html#implementations) and [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html#implementations) for more.

[View full post](https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums)

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Daniel Cormier"
  },
  "dateModified" : "2026-06-04T10:36:57.278Z",
  "datePublished" : "2022-01-28T20:43:51Z",
  "headline" : "On Rust's Option and Result Enums",
  "image" : {
    "@type" : "ImageObject",
    "height" : 675,
    "url" : "https://www.knowbe4.com/hubfs/engineering-post.jpg",
    "width" : 1200
  },
  "mainEntityOfPage" : "https://www.knowbe4.com/careers/blogs/engineering/on-rusts-option-and-result-enums",
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "height" : 60,
      "url" : "/hs/hsstatic/content_shared_assets/static-1.4092/img/default-amp-logo.png",
      "width" : 60
    },
    "name" : "KnowBe4 Engineering Blog"
  }
}
```