Operator ? in for_each

Hello!
How to handle the operator ? in the for_each function?

Code:

fn main() 
{
    let v = vec![vec!["1", "2", "3"], vec!["4", "5", "6"], vec!["7", "8", "9"]];

    let do_something = |name: &String| -> Result<u8, String>  
    {
        let n : u8 = name.parse().map_err(|_|{ format!("cannot convert!") })?;
        
        if n == 42 { return Err("Error!!!!!".to_string()); }
        
        return Ok(n);
    };   
    
    let print = |v: Vec<Vec<&str>>| -> Result<(), String>
    {
        v.iter().for_each(|v1|{
            println!("vec:");
            v1.iter().for_each(|v2|{ 
                println!("\t {:?}", v2);
                do_something(&v2.to_string())?;
            });
        });
        
        return Ok(());
    };
    
    let _error_msg = print(v);
}

Error:

error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
  --> src/main.rs:21:17
   |
19 |               v1.iter().for_each(|v2|{ 
   |  ________________________________-
20 | |                 println!("\t {:?}", v2);
21 | |                 do_something(&v2.to_string())?;
   | |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a closure that returns `()`
22 | |             });
   | |_____________- this function should return `Result` or `Option` to accept `?`
   |
   = help: the trait `std::ops::Try` is not implemented for `()`
   = note: required by `std::ops::Try::from_error`

Rust Playground: CLICK ME!

The simplest solution is to use for loops:

for v1 in &v {
    println!("vec:");
    for v2 in v1 { 
        println!("\t {:?}", v2);
        do_something(&v2.to_string())?;
    }
}

Another alternative is to use Iterator::try_for_each:

v.iter().try_for_each(|v1| {
    println!("vec:");
    v1.iter().try_for_each(|v2| -> Result<(), String> { 
        println!("\t {:?}", v2);
        do_something(&v2.to_string())?;
        Ok(())
    })
})?;        

(But seriously, use a for loop. It's usually more readable, and in addition to ? it also gives you the ability to use other control-flow features like break and continue (with optional labels) and early return and so on.)

5 Likes

Or map and collect

v.iter()
    .map(|v1| {
        println!("vec:");
        v1.iter()
            .map(|v2| {
                println!("\t {:?}", v2);
                do_something(&v2.to_string())?;
                Ok(())
            })
            .collect::<Result<(), String>>()
    })
    .collect::<Result<(), String>>()?;
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.