Bailing from an iter chain

I mean working in Result / ? / anyhow land inside an iter chain. How to make this work?

fn noodle_something() -> Result<()> {
....
   let stuff = collection.iter().filter(|i| i > 42).map(|i| {
           let f = foodle(i);
           if f.is_somethingwrong(){
                 bail!("cant froodle a noodle");
           f
  }
....
}

I dont think this can be made to work because the lambdas for iters are not Result returning, but I know that rust is extremely idiomatic and there may be ways to do this that I cannot see

Result<V, E>V being the collection you collect your Ok(T) instances into—can be collected from an iterator with Result<T, E> elements. Collecting Result<V, E> is short-circuiting, it stops after the first Err is encountered.

2 Likes

I dont follow what you are trying to say, could you edit my example to demonstrate it

#[derive(Debug)]
struct Foodle {
    is_somethingwrong: bool,
}

fn foodle(_: i32) -> Foodle {
    Foodle {
        is_somethingwrong: true,
    }
}

fn main() -> Result<(), anyhow::Error> {
    let collection = vec![0, 1, 2, 3];

    let _stuff = collection
        .iter()
        .filter(|i| **i < 42)
        .map(|i| {
            let f = foodle(*i);
            if f.is_somethingwrong {
                anyhow::bail!("cant froodle a noodle");
            }
            Ok(f)
        })
        .collect::<Result<Vec<Foodle>, anyhow::Error>>()?;
    
    Ok(())
}

Playground.

4 Likes

Thank you, how do I make this work


                let (ptype, pnames) = params
                    .iter()
                    .map(|p| {
                        let (name, ptype, _) = self.process_declarator(&p.decl, base_type)?;
                        (ptype, name)
                    })
                    .unzip();

this fails to compile due to the '?' on the process_declarator call

    fn process_declarator(
        &mut self,
        decl: &Declarator,
        base_type: &SymbolType,
    ) -> Result<(String, SymbolType, Vec<String>)>

I dont see how to use your solution here

To handle errors, yoy can use filter_map instead of map

If your definition of "handling errors" is just filtering them out and ignoring them, then filter_map works here.


You can use try_fold since unzip() is an eager operation:

let (ptype, pnames) = params.iter()
    .try_fold((vec![], vec![]), |(mut types, mut names), p| {
        let (name, ptype, _) = self.process_declarator(&p.decl, base_type)?;
        names.push(name);
        types.push(ptype);
        Ok((types, names))
    });

Or itertools::process_results (untested):

let (ptype, pnames) = params.iter()
    .map(|p| {
        let (name, ptype, _) = self.process_declarator(&p.decl, base_type)?;
        (ptype, name)
    })
    .process_results(|it| it.unzip())?;
1 Like