How can I filter an iterator when the predicate returns a Result<bool, _>?

こ雲淡風輕ζ 提交于 2021-02-19 05:00:05

问题


I would like the iterator to be filtered, but my predicate has the possibility of failing. When the predicate fails, I'd like to fail the entire function. In this example, I'd like work to return the Result generated by maybe:

fn maybe(v: u32) -> Result<bool, u8> {
    match v % 3 {
        0 => Ok(true),
        1 => Ok(false),
        2 => Err(42),
    }
}

fn work() -> Result<Vec<u32>, u8> {
    [1, 2, 3, 4, 5].iter().filter(|&&x| maybe(x)).collect()
}

fn main() {
    println!("{:?}", work())
}
error[E0308]: mismatched types
  --> src/main.rs:10:45
   |
10 |         [1, 2, 3, 4, 5].iter().filter(|&&x| maybe(x)).collect()
   |                                             ^^^^^^^^ expected bool, found enum `std::result::Result`
   |
   = note: expected type `bool`
              found type `std::result::Result<bool, u8>`

error[E0277]: the trait bound `std::result::Result<std::vec::Vec<u32>, u8>: std::iter::FromIterator<&u32>` is not satisfied
  --> src/main.rs:10:55
   |
10 |         [1, 2, 3, 4, 5].iter().filter(|&&x| maybe(x)).collect()
   |                                                       ^^^^^^^ a collection of type `std::result::Result<std::vec::Vec<u32>, u8>` cannot be built from an iterator over elements of type `&u32`
   |
   = help: the trait `std::iter::FromIterator<&u32>` is not implemented for `std::result::Result<std::vec::Vec<u32>, u8>`

回答1:


You can turn the Result<bool, u8> into an Option<Result<u32, u8>>, that is, pull the bool out to an Option and put the value inside, and use filter_map:

fn maybe(v: u32) -> Result<bool, u8> {
    match v % 3 {
        0 => Ok(true),
        1 => Ok(false),
        _ => Err(42),
    }
}

fn work() -> Result<Vec<u32>, u8> {
    [1, 2, 3, 4, 5]
        .iter()
        .filter_map(|&x| match maybe(x) {
            Ok(true) => Some(Ok(x)),
            Ok(false) => None,
            Err(e) => Some(Err(e)),
        })
        .collect()
}

fn main() {
    println!("{:?}", work())
}

playground



来源:https://stackoverflow.com/questions/28036173/how-can-i-filter-an-iterator-when-the-predicate-returns-a-resultbool

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!