ayosec
August 2, 2021, 2:22pm
1
Hi everyone!
Given this code:
fn do_something(item: T) { }
fn items() -> impl Iterator<Item = Result<T, E>> {
// …
}
fn use_items() -> Result<(), E> {
for item in items() {
let item = item?; // ←
// now, `item` is `T`
do_something(item);
}
Ok(())
}
Is there any way to remove the let item = item?
line? So I can write something like this:
fn use_items() -> Result<(), E> {
for item in items().[???] {
do_something(item);
}
Ok(())
}
No, not really. The let item = item?;
should be pretty idiomatic AFAIK.
2 Likes
I personally often desugar the for-loop, (and the same technique works with async iterators).
let iter = items();
while let Some(item) = iter.next()? {
This doesn’t do anything to handle any Err(…)
items. And if you’d just use a while let Some(Ok(…))
-style pattern, you’d be ignoring, not propagating the errors. Wait, I missed the “?
”. But aren’t you missing something like a .transpose()
call?
while let Some(item) = iter.next().transpose()? {…}
Maybe, I definitely feel like I've at least done .next().await?
on a stream before and had it work but maybe I'm thinking of something out of context.
You can use itertools::Itertools::map_ok like this:
use itertools::Itertools;
fn use_items() -> Result<(), E> {
items().map_ok(|item| {
do_something(item);
}).collect()
}
or in this simple case, even:
fn use_items() -> Result<(), E> {
items().map_ok(do_something).collect()
}
(Playground)
2 Likes
If you want to do this in non-terminal position in the function, then try_collect
can help with type inference.
fn use_items() -> Result<(), E> {
items().map_ok(|item| {
do_something(item);
}).try_collect()?;
// do something else here, too…
Ok(())
}
Note that this approach (with either of the collect
functions) doesn’t work as nicely if you had any other usage of ?
or perhaps break
or return
in the for
-loop.
system
Closed
October 31, 2021, 3:08pm
8
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.