Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust: iterating over iter() or vector itself

I was watching a Rust lecture and seen I think two ways of iterating over a vector. I could iterate over "vector itself" or over "iter() method". Could you please tell me what is the difference here?

fn call(from: &mut Vec<i32>, to: &mut Vec<i32>) {
    for e in from.iter() {
        to.push(*e);
    }
    for e in from {
        to.push(*e);
    }
}

fn printvec(from: & Vec<i32>) {
    for e in from {
        print!("{} ", e);
    }
    println!("");
}

fn main() {
    let mut v1 = vec![1,2,3];
    let mut v2 = vec![1,2,3];
    call(&mut v1, &mut v2);
    printvec(&v1);
    printvec(&v2);
}
like image 475
ArekBulski Avatar asked Jun 16 '26 00:06

ArekBulski


2 Answers

Could you please tell me what is the difference here?

Here there is no difference as Stargateur notes. To know what's happening, you simply need to follow the white rabbit trait implementation: Rust's for loop "simply" calls IntoIterator on the "RHS". Now if we go down the list of implementors

We can see an implementation for &Vec

It's not documented per-se but looking at the code it just calls self.iter(), so here we do have the confirmation that Stargateur is correct, &Vec and Vec::iter do the exact same thing

Vec::iter

The documentation is a bit terse but it links to std::slice::Iter which is "Immutable slice iterator", not necessarily super helpful in and of itself but the trait implementation is pretty clear

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T
}

So Vec<T>::iter -> Iter<T> -> Iterator<Item=&a>, meaning when you .iter() a vector (or you iterate an &Vec) you iterate on immutable references to the items. And since iter takes &self (and &Vec is obviously a reference) it also means that the iteration only borrows the vector, so once you're done iterating the vector is still there unchanged.

&mut Vec and Vec::iter_mut

Though you didn't mention it that's the second iterator, it's similar to the one above except it yields a std::slice::IterMut which

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T
}

so instead of yielding immutable references to items it yields mutable ones, which means you can modify items in-place, e.g. increment them, pretty cool.

Vec itself

So we come to this, and if you expand the definition you see essentially this:

impl<T> IntoIterator for Vec<T> {
    type Item = T
    type IntoIter = IntoIter<T, A>

    pub fn into_iter(self) -> IntoIter<T, A>

Creates a consuming iterator, that is, one that moves each value out of the vector (from start to end). The vector cannot be used after calling this.

Which is pretty self-explanatory: if you iterate on the Vec directly it consumes the vector, meaning you will not be able to use it afterwards.

In return, however, it moves the ownership of the vector's items into the iterator, which provides more flexibility.

like image 110
Masklinn Avatar answered Jun 18 '26 22:06

Masklinn


From the Rust Reference:

'label: for PATTERN in iter_expr {
    /* loop body */
}

is equivalent to

{
    let result = match IntoIterator::into_iter(iter_expr) {
        mut iter => 'label: loop {
            let mut next;
            match Iterator::next(&mut iter) {
                Option::Some(val) => next = val,
                Option::None => break,
            };
            let PATTERN = next;
            let () = { /* loop body */ };
        },
    };
    result
}

The difference between your for loops is that in one the iter_expr is from and in the other it is from.iter(). IntoIterator is implemented like this for a vector reference:

impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
    type Item = &'a T;
    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.iter()
    }
}

Note that it's calling self.iter(), so there is no difference between this iterator and the one you get from your from.iter() for loop.

like image 43
Ben Avatar answered Jun 18 '26 22:06

Ben



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!