Using '?' in try_ enclousers

I iterate over arrays in enclosures as below:

let data = [Some("no_tea.txt"), None, None, Some("stale_bread.json"), Some("torrential_rain.png")];
        let mut res = String::from("");
        data.iter().try_for_each(|each| {
            if each.is_none() { return ControlFlow::<()>::Continue(()) }
            let val = each.unwrap(); //as_deref()?;
            res.push_str(&format!{"loading {val}... "});
            ControlFlow::Continue(())
            }
        );

The code looks ugly for my taste and I would prefer using '?". However using:

let val = each.as_deref()?;

gives me:

error[E0277]: the ? operator can only be used on ControlFlows in a closure that returns ControlFlow
--> cookie.rs:60:38
|
59

| data.iter().try_for_each(|each| {
| ------ this function returns a `Contr

olFlow`
60 | let val = each.as_deref()?;
| ^ th

is ? produces Option<Infallible>, which is incompatible with ControlFlow<_>

|

= help: the trait FromResidual<Option<Infallible>> is not implemented for ControlFlow<_>

= help: the trait FromResidual<ControlFlow<_, Infallible>> is implemented for ControlFlow<_>

= help: for that trait implementation, expected ControlFlow<_, Infallible>, found Option<Infallible>

Any idea how can I fix the error?

You could use let-else:

// return type only needed because there's no breaks
data.iter().try_for_each(|each| -> ControlFlow<(), ()> {
	let &Some(val) = each else {
		return ControlFlow::Continue(());
	};
	res.push_str(&format! {"loading {val}... "});
	ControlFlow::Continue(())
});

But I'd probably just use Option or Result.

data.iter().try_for_each(|each| {
	let val = each.as_deref()?;
	res.push_str(&format! {"loading {val}... "});
	Some(())
});

If you actually don't have any breaks, just use for_each.

1 Like

Thanks, the first variant works as expected, although there is no '?".
The second one is a syntaxly correct, however '?' works like a break. Is there a way to treat it as the continue?

Oh right, no, that's pretty much hardcoded into the Try trait and try_for_each. Another thing you can do is flatten the iterator, which has the effect of ignoring None items.

data.iter().flatten().try_for_each(|&val| {
    res.push_str(&format!("loading {val}... "));
    Some(())
});

Or maybe flat_map.

let () = data
    .iter()
    .flat_map(|each| {
        let val = each.as_deref()?;
        res.push_str(&format! {"loading {val}... "});
        Some(())
    })
    .collect();
1 Like

Thank you for confirming that it isn't possible to reverse the logic using the continue instead of the break. The example I gave just a mock up example of using '?' in a closure. I do not need a work around. I just wanted to know that I didn't miss something meaningful.

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.