Hacker News new | past | comments | ask | show | jobs | submit login

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).

  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; unfortunately the link is dead and I can't find it on the domain




> 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


Thanks for taking the time to explain!


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: