How to implement some convenient methods (e.g., flat_map, flatten) on Option?

rust

Solution

These probably already exist, just as different names to what you expect. Check the docs for Option.

You'll see `flat_map` more normally as `and_then`:

let x = Some(1);
let y = x.and_then(|v| Some(v + 1));

The bigger way of doing what you want is to declare a trait with the methods you want, then implement it for `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);
}

For `flatten`, I'd probably write:

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

But if you wanted a trait:

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

Would there be a way to allow flatten to arbitrary depth

See How do I unwrap an arbitrary number of nested Option types?

Problem

It would be nice if Rust's `Option` provided some additional convenience methods like `Option#flatten` and `Option#flat_map`, where `flatten` would reduce an `<Option<Option<T>>` to `Option<T>`, and `flat_map` would work like `map`, but takes a method/closure that returns an `Option` and flattens it. `flat_map` is pretty straightforward: ``` 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` is more complex, and I don't really know how to go about defining it. It might look something like: ``` fn opt_flatten<T, U>(opt: Option<T>) -> Option<U> { match opt { Some( Some(x) ) => flatten_option( Some(x) ), _ => opt } } ``` But that certainly doesn't work. Any thoughts? Also, how would I go about implementing these methods on the `Option` enum, so that I can use them natively on an `Option` instance? I know I need to add the type signature in somewhere around `impl OptionExts for Option<T>`, but I'm at a loss... Hope this makes sense and I apologize for my imprecise terminology--I'm brand new to Rust.

Original source

Related problems