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

时间:2015-02-17 16:45:55

标签: rust

如果Rust Option提供了一些额外的便利方法,例如Option#flattenOption#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枚举上实现这些方法,以便我可以在Option实例上原生使用它们?我知道我需要在impl OptionExts for Option<T>附近的某处添加类型签名,但我不知所措......

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

2 个答案:

答案 0 :(得分:4)

这些可能已经存在,就像你期望的那样。查看docs for Option

您会flat_map更正常地看到and_then

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

做你想做的更大的方法是用你想要的方法声明 trait ,然后为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);
}
  

是否有办法让平坦到任意深度

请参阅How do I unwrap an arbitrary number of nested Option types?

答案 1 :(得分:4)

fn flatten<T>(x: Option<Option<T>>) -> Option<T> {
    x.unwrap_or(None)
}

就我而言,我正在处理Option中的unwrap_or_else - 返回方法,忘记了普通的or_else方法。