Как реализовать некоторые удобные методы (например, flat_map, flatten) в Option?
Было бы неплохо, если бы Rust's Option
предоставлены некоторые дополнительные удобные методы, такие как Option#flatten
а также Option#flat_map
, где flatten
уменьшит <Option<Option<T>>
в Option<T>
, а также flat_map
будет работать как map
, но принимает метод / замыкание, которое возвращает Option
и выравнивает это.
flat_map
довольно просто:
fn opt_flat_map< T, U, F: FnOnce(T) -> Option<U> >(opt: Option<T>, f: F) -> Option<U> {
match opt {
Some(x) => f(x),
None => None
}
}
flatten
является более сложным, и я не знаю, как его определить. Это может выглядеть примерно так:
fn opt_flatten<T, U>(opt: Option<T>) -> Option<U> {
match opt {
Some( Some(x) ) => flatten_option( Some(x) ),
_ => opt
}
}
Но это, конечно, не работает. Какие-нибудь мысли?
Кроме того, как бы я пошел о реализации этих методов на Option
enum, так что я могу использовать их изначально на Option
пример? Я знаю, что мне нужно добавить сигнатуру типа где-то вокруг impl OptionExts for Option<T>
, но я в растерянности...
Надеюсь, что это имеет смысл, и я прошу прощения за мою неточную терминологию - я новичок в Rust.
2 ответа
Они, вероятно, уже существуют, так же, как разные имена, чем вы ожидаете. Проверьте документы для варианта.
Вот увидишь flat_map
как обычно and_then
:
let x = Some(1);
let y = x.and_then(|v| Some(v + 1));
Лучший способ сделать то, что вы хотите, это объявить черту с методами, которые вы хотите, а затем реализовать его для Option
:
trait MyThings {
fn more_optional(self) -> Option<Self>;
}
impl<T> MyThings for Option<T> {
fn more_optional(self) -> Option<Option<T>> {
Some(self)
}
}
fn main() {
let x = Some(1);
let y = x.more_optional();
println!("{:?}", y);
}
За flatten
Я бы наверное написал:
fn flatten<T>(opt: Option<Option<T>>) -> Option<T> {
match opt {
None => None,
Some(v) => v,
}
}
fn main() {
let x = Some(Some(1));
let y = flatten(x);
println!("{:?}", y);
}
Но если вы хотели черту:
trait MyThings<T> {
fn flatten(self) -> Option<T>;
}
impl<T> MyThings<T> for Option<Option<T>> {
fn flatten(self) -> Option<T> {
match self {
None => None,
Some(v) => v,
}
}
}
fn main() {
let x = Some(Some(1));
let y = x.flatten();
println!("{:?}", y);
}
Был бы способ позволить сгладить до произвольной глубины
См. Как развернуть произвольное количество вложенных типов Option?
fn flatten<T>(x: Option<Option<T>>) -> Option<T> {
x.unwrap_or(None)
}
В моем случае я имел дело с Option
возвратный метод в unwrap_or_else
и забыл про равнину or_else
метод.