如何在 Option 上实现一些方便的方法(例如 flat_map、flatten)?

Jac*_*own 2 rust

如果 RustOption提供了一些额外的便利方法,比如Option#flattenand Option#flat_map,那么这将是很好的, whereflatten会将 an 减少<Option<Option<T>>Option<T>,并且flat_map会像 一样工作map,但采用返回 anOption并将其展平的方法/闭包。

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
  }
}
Run Code Online (Sandbox Code Playgroud)

flatten更复杂,我真的不知道如何定义它。它可能看起来像:

fn opt_flatten<T, U>(opt: Option<T>) -> Option<U> {
  match opt {
      Some( Some(x) ) => flatten_option( Some(x) ),
      _ => opt
  }
}
Run Code Online (Sandbox Code Playgroud)

但这肯定行不通。有什么想法吗?

另外,我将如何在Option枚举上实现这些方法,以便我可以在Option实例上本地使用它们?我知道我需要在周围的某个地方添加类型签名impl OptionExts for Option<T>,但我不知所措......

希望这是有道理的,我为我不精确的术语道歉——我是 Rust 的新手。

Dem*_*med 7

fn flatten<T>(x: Option<Option<T>>) -> Option<T> {
    x.unwrap_or(None)
}
Run Code Online (Sandbox Code Playgroud)

就我而言,我正在处理Option-returning 方法unwrap_or_else并忘记了普通or_else方法。


She*_*ter 5

这些可能已经存在,就像您期望的名称不同。检查Option文档

你会flat_map更正常地看到and_then

let x = Some(1);
let y = x.and_then(|v| Some(v + 1));
Run Code Online (Sandbox Code Playgroud)

做你想做的更大的方法是用你想要的方法声明一个特征,然后实现它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);
}
Run Code Online (Sandbox Code Playgroud)

对于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);
}
Run Code Online (Sandbox Code Playgroud)

但如果你想要一个特质:

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);
}
Run Code Online (Sandbox Code Playgroud)

有没有办法允许展平到任意深度

请参阅如何解开任意数量的嵌套 Option 类型?