for (i, x) in something.iter_mut().filter(|| {...}).enumerate() {
*x = (*x) * i
}
The `mut` keyword isn't needed here because, I assume if the above assumption is correct, "iter_mut()" is returning a mutable iterator. Is there some reason the result of "something.iter_mut().filter(|| {...}).enumerate()" can't be saved to a variable and then used as the "something" in the first example?
Anyway, this post reminds me of an article, "Why Programming Language X is Unambiguously Better Than Programming Language Y"[0]. Mostly talking about how [poorly written Y code] is why Y is a bad language and [beautiful and elegant X code] is why X is a good language.
> Is there some reason the result of "something.iter_mut().filter(|| {...}).enumerate()" can't be saved to a variable and then used as the "something" in the first example?
You absolutely can do something like `let iter = something.iter_mut().filter(|| {...}).enumerate();` In Rust, Iterators are just need to implement a Trait (kindof like an Go or Java interface) so they can be put in normal variables just fine.
> The `mut` keyword isn't needed here because, I assume if the above assumption is correct, "iter_mut()" is returning a mutable iterator.
Every for loop implicitly calls `.into_iter()` on the thing to loop over; the docs are decent at explaining what IntoIter is [0]. By doing `&mut something` instead of just `something` you get a different IntoIter implementation which has very different semantics. Typically `(&mut something).into_iter()` would have the same behavior and might even result in the same type as `something.iter_mut()`.
Like mentioned below, for loops desugar to something that ends up calling the "into_iter" method on the type. In rust &mut T, &T and T are different types, so the "into_iter" method is actually different for each one!
Here is an example to illustrate what I mean (i did not test to see if it compiles so there may be some mistakes):
struct Foo<T>(Vec<T>);
impl IntoIterator for Foo<T> {
type IntoIter = std::vec::IntoIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Foo<T> {
type IntoIter = std::slice::Iter<'a, T>;
type Item = &'a T;
fn into_iter(self) -> Self::IntoIter {
self.0.as_slice().iter()
}
}
impl<'a> IntoIterator for &'a mut Foo<T> {
type IntoIter = std::slice::IterMut<'a, T>;
type Item = &'a T;
fn into_iter(self) -> Self::IntoIter {
self.0.as_slice().iter_mut()
}
}
Doing "for x in T" calls the first method, "for x in &T" calls the second, and "for x in &mut T" calls the last one.
As you see here, each IntoIterator returns a completely different type, and the first IntoIterator actually consumes the struct Foo as well!
There are also the methods "iter" and "iter_mut", these are just there for convention and technically don't need to exist for the iterator related traits. It's useful for doing iterator pipelines that don't have any for loop.
Anyway, this post reminds me of an article, "Why Programming Language X is Unambiguously Better Than Programming Language Y"[0]. Mostly talking about how [poorly written Y code] is why Y is a bad language and [beautiful and elegant X code] is why X is a good language.
[0] https://news.ycombinator.com/item?id=6960398; unfortunately the link is dead and I can't find it on the domain