3 ms·
I'm not familiar with Rust. for x in &mut something { *x = (*x) * 2; } Here (above) it looks like the `&mut` is allowing the iterator to be mutabl
by lcnPylGDnU4H9OF 4y ago
I'm not familiar with Rust.
for x in &mut something {
*x = (*x) * 2;
}
Here (above) it looks like the `&mut` is allowing the iterator to be mutable (https://doc.rust-lang.org/std/keyword.mut.html https://doc.rust-lang.org/std/keyword.mut.html).
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.
[0] https://news.ycombinator.com/item?id=6960398 https://news.ycombinator.com/item?id=6960398; unfortunately the link is dead and I can't find it on the domain
- thethirdone 4y ago> 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()`. [0]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
- lcnPylGDnU4H9OF 4y agoThanks for taking the time to explain!
- chlorion 4y agoLike 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.