Reverse iterating over a &vec versus vec.iter()
Asked Answered
W

3

26

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?

Whitsun answered 29/9, 2016 at 16:1 Comment(0)
R
26

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.

Responsiveness answered 29/9, 2016 at 16:6 Comment(0)
H
16

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.

Harness answered 29/9, 2016 at 16:6 Comment(1)
This is not just precedence, even if you add parentheses this won't compile because &vec isn't an iterator (only IntoIterator).Tibetan
H
0

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);
    }    
}
Hypaethral answered 19/7 at 13:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.