I have an enum with two different possible "types" and a function that may return any of them, wrapped in an Option
:
enum Possibilities {
First(i32),
Second(String),
}
use Possibilities::*;
fn some_poss() -> Option<Possibilities> {
Some(Second(String::from("hi")))
}
I want to apply an operation to the result of some_poss
, but this operation only makes sense for one of the possibilities of the enum, otherwise it should return None
. For example:
let a: Option<i32> = some_poss().and_then(|poss| if let First(x) = poss {
Some(x * 2)
} else {
None
});
How can I concisely combine this operation? Would it be possible to write this in a way similar to the following?
// Compile error: pattern `Second(_)` not covered
let b: Option<i32> = some_poss().map(|First(x)| x * 2);
The best way to handle this specific case would be to create a method on the enum
specifically for retrieving the one variant. Somewhat like Result::ok
.
enum Possibilities {
First(i32),
Second(String),
}
use Possibilities::*;
impl Possibilities {
fn first(self) -> Option<i32> {
match self {
Possibilities::First(x) => Some(x),
_ => None,
}
}
}
This would allow you to implement your function like:
some_fun().and_then(|p| p.first()).map(|x| x * 2)
// or, if you prefer this style:
some_fun().and_then(Possibilities::first).map(|x| x * 2);
This makes it explicit what each step is doing - some_poss
gets an Option<Possiblities>
, then first()
gets an Option<i32>
from that Possibilities
, and then and_then
collapses Option<Option<i32>>
into Option<i32>
.