HiDefender
HiDefender

Reputation: 2368

Reverse iterating over a &vec versus vec.iter()

This works because Iterator implements rev() where self is a DoubleEndedIterator:

let vec: Vec<i32> = Vec::new();
for x in vec.iter().rev() {
    //Do stuff
}

However, if I change vec.iter().rev() to &vec.rev() it won't compile because:

no method named `rev` found for type `std::vec::Vec<i32>` in the current scope

Furthermore:

the method `rev` exists but the following trait bounds were not satisfied: `std::vec::Vec<i32> : std::iter::Iterator`, `[i32] : std::iter::Iterator`

But doesn't a for loop implicitly call IntoIterator? Is &vec or vec.iter() considered idiomatic Rust?

Upvotes: 27

Views: 25539

Answers (3)

Olivier Lasne
Olivier Lasne

Reputation: 981

As indicated by the others answer, it is due to the precedence of the & operator.

You can use parenthesis to clarify that & is referring to v and not the result of rev().

This won't compile:

let vec: Vec<i32> = Vec::new();
for x in &vec.iter().rev() {
    //Do stuff
}

This will compile:

let vec: Vec<i32> = Vec::new();
for x in (&vec).iter().rev() {
    //Do stuff
}

It also works if the reference is a variable. As there is no ambiguity that & is referring to v:

fn main() {
    let v = vec!["Can", "I", "talk", "backward"];
    let yoda = &v; // reference to the vector

    for word in yoda.into_iter().rev() {
        println!("{}", word);
    }    
}

Upvotes: 1

Shepmaster
Shepmaster

Reputation: 430290

This is just basic precedence of the & operator. In the first case, each method is called in turn:

vec.iter().rev()
(vec.iter()).rev() // same

In the second case, the & binds after all the methods:

&vec.rev()
&(vec.rev()) // same

Generally, use &vec when you can, but when you need to use iterator adapter methods, use iter or into_iter.

Upvotes: 16

Chris Emerson
Chris Emerson

Reputation: 14021

If you're just looping over the Vec, then &vec is idiomatic. This works because &Vec<T> implements IntoIterator, which is what the for loop uses.

However if you want to call Iterator methods such as rev, filter, etc., you need an actual Iterator (since Vec doesn't implement Iterator, only IntoIterator).

So this:

for x in &vec.rev() {
    ...
}

is equivalent to:

for x in (&vec.rev()).into_iter() {
    ...
}

i.e. there's no chance to use IntoIterator before trying to call Iterator methods.

Upvotes: 27

Related Questions