-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve eagerly evaluating an iterator for its side-effects #44546
Comments
Making collect |
I suspect that most of the time you might reach for this, there will probably be a
It's not an antipattern for an |
Just a comment on naming... 🚲 🚲 🚲 |
.exhaust() is my favourite name (by @tbu-). On balance I think this method would be a win, although I am also hoping that See also previous discussion in rust-itertools/itertools/pull/131 |
I think we should have a dedicated name for this, even |
As of #45379 there is let mut sum = 0;
(0..10).map(|x| sum += x).collect::<()>();
println!("{}", sum); It is slightly more handy than use std::io::*;
let res: Result<()> = (0..10)
.map(|x| writeln!(stdout(), "{}", x))
.collect();
assert!(res.is_ok()); Does that address the request in this issue or do we feel that there is more room for improvement? |
I'd still say that it's annoying to type, compare |
And collect to unit is hard to discover, too, isn't it? (It is kind of automatically available if one calls collect(); maybe that would be the only intuitive entry.) |
I would be prepared to consider a PR for |
So basically revive #45168 and change the name to |
Closed by #48945, where it was decided that |
iterators4.rs was particularly instructive. I started out by searching for the initial C recursion and for loop versions and tried to use a range iteration but couldn't figure the syntax. So I created the first 7 answers and then used hint. I then seached for: how to use iterator for side effects only https://www.google.com/search?q=how+to+use+iterator+for+side+effects+only+in+rust And saw this: rust-lang/rust#44546 (comment) And: rust-lang/rust#44546 (comment) And with that I implemented Answer 8 But still wasn't happy as I felt there must be a better way where I didn't need to throw away things. So I looking at the iterator documentation: https://doc.rust-lang.org/std/iter/trait.Iterator.html I saw "fold" and low and behold that was exactly what I needed! Then I saw "fold_first" and it was "simpler" as the first value in the range is the initial value for the accumulator so fold_first only has one parameters not two. But fold_first returns an Option which means I need to return the unwrap(). Anyway both Answers 9 and 10 are simpler then any other solution! I do wonder which is fastest.
0b_0101_001_1010 had a good idea on Reddit. I'll paraphrase it here.
The only way to eagerly consume an iterator, e.g., for its side-effects, on stable Rust is to call
.collect
or.count
(.for_each
is nightly only). Most beginners don't associate.count
with this, so they use.collect
, which is horrible.There are a few things we could do to help make it more obvious what the correct thing to do is:
.collect
's result#[must_use]
. If you are throwing.collect
's result away, you are doing it wrong, and should not have used.collect
in the first place. A loop or.for_each
would do..count
's result#[must_use]
: while.count
is "efficent" (when compared to.collect
) it doesn't convey what the code is actually doing.eval()
==.for_each(|_|)
: because.for_each(|_|)
is also ugly.collect
means copy the results of the iterator into a collection, not "eagerly evaluate", or similarThe text was updated successfully, but these errors were encountered: