Why does into_iter() not return type T?

From this topic, I guess Vec<i32>.into_iter() would return i32 type.
https://doc.rust-lang.org/std/iter/index.html#the-three-forms-of-iteration

  • iter() , which iterates over &T .
  • iter_mut() , which iterates over &mut T .
  • into_iter() , which iterates over T .

But as following, I find that into_iter() depend on the context , and iter(), iter_mut() work fine.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a0ae390e8dca9d5b8183842c82194210

fn into_iter_mut(v: &mut Vec<i32>) {
    for i in v.into_iter(){
        // expected `i32`, found `&mut i32`
        let a:i32 = i;
    }
    
    for i in v.iter(){
        // expected `i32`, found `&i32`
        let a:i32 = i;
    }
    
    for i in v.iter_mut(){
        // expected `i32`, found `&mut i32`
        let a:i32 = i;
    }
}

fn into_iter_ref(v: &Vec<i32>) {
    for i in v.into_iter(){
        // expected `i32`, found `&i32`
        let a:i32 = i;
    }
    
    for i in v.iter(){
        // expected `i32`, found `&i32`
        let a:i32 = i;
    }
    
    for i in v.iter_mut(){
        // expected `i32`, found `&mut i32`
        let a:i32 = i;
    }
}

fn into_iter(v: Vec<i32>) {
    for i in v.into_iter(){
        // expected `i32`, found `i32`
        let a:i32 = i;
    }
    
    for i in v.iter(){
        // expected `i32`, found `&i32`
        let a:i32 = i;
    }
    
    for i in v.iter_mut(){
        // expected `i32`, found `&mut i32`
        let a:i32 = i;
    }
}

fn main() {}
1 Like

Each of Vec<T>, &Vec<T>, and &mut Vec<T> has its own IntoIterator implementation, returning T, &T, and &mut T respectively.

6 Likes

And indeed you couldn't call Vec's own IntoIterator through a reference even by manually dereferencing it, because you cannot consume (move) what you're only borrowing. And consuming self is the true defining semantic of IntoIterator; if you just want copies or clones of the elements, that can be done for any iterator using the copied() and cloned() adapters respectively.

2 Likes

Well, it is possible to move out of something behind a mutably reference, you just also have to move something else in at the same time using mem::swap or mem::replace or mem::take. E.g.

fn into_iter_mut(v: &mut Vec<i32>) {
    for i in std::mem::take(v).into_iter() {
        // compiles fine
        let a: i32 = i;
    }
}

(playground)

@z-Wind
In this case, there’s also the alternative of using Vec::drain (so: β€œfor i in v.drain(..) {”) that keeps the allocation in place, or in the specific case of i32, you can use for i in v.iter().copied() even with the immutable reference. Also note that having functions with &Vec<i32>-arguments, i.e. shared reference to Vec, is an antipattern in general, you’d usually want to change that to &[i32] instead. Finally note that into_iter() is often redundant when for loops are used, since

for i in 𝑒π‘₯π‘π‘Ÿ {…}

desugars to something similar to

let iterator = 𝑒π‘₯π‘π‘Ÿ.into_iter();
while let Some(i) = iterator.next() {…}

This – together with the IntoIter implementations that @2e71828 mentioned – allows for nice for loops without any need for explicit iter or iter_mut calls like this:

let v = vec![1,2,3];
for i in &v {
    // i: &i32
}
for i in &mut v {
    // i: &mut i32
}
for i in v { // <- consumes / moves out of `v`
    // i: i32
}
7 Likes