Составление Option<Enum> с замыканиями, которые сопоставляют аргументы с образцом

У меня есть enum с двумя различными "типами" и функцией, которая может возвращать любой из них, завернутый в Option:

enum Possibilities {
    First(i32),
    Second(String),
}
use Possibilities::*;

fn some_poss() -> Option<Possibilities> {
    Some(Second(String::from("hi")))
}

Я хочу применить операцию к результату some_poss, но эта операция имеет смысл только для одной из возможностей перечисления, в противном случае она должна вернуться None, Например:

let a: Option<i32> = some_poss().and_then(|poss| if let First(x) = poss {
    Some(x * 2)
} else {
    None
});

Как я могу кратко объединить эту операцию? Можно ли написать это так, как показано ниже?

// Compile error: pattern `Second(_)` not covered
let b: Option<i32> = some_poss().map(|First(x)| x * 2);

1 ответ

Решение

Лучший способ справиться с этим конкретным случаем - создать метод на enum специально для получения одного варианта. Что-то вроде 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,
        }
    }
}

Это позволит вам реализовать вашу функцию как:

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);

Это делает явным то, что делает каждый шаг - some_poss получает Option<Possiblities>, затем first() получает Option<i32> От этого Possibilities, а потом and_then обвалы Option<Option<i32>> в Option<i32>,

Другие вопросы по тегам