Into_iter() and iter() produces same data type

I tested the following code but both for loops produced same data type which is &i32.
AFAIK, into_iter() should consume the data but it didn't.
Could someone explain why?

fn main() {
    let v = vec![1, 2, 3];
    sub(&v);
}

fn sub(v: &Vec<i32>) {
    for n in v.into_iter() {  // <-- into_iter() does not consume v and n is &i32
        print!("{n}");
    }

    for n in v.iter() {
        print!("{n}");
    }
}

Thanks in advance

v has type &Vec<i32> so naturally you are calling <&Vec<i32> as IntoIterator>::into_iter instead of <Vec<i32> as IntoIterator>::into_iter which consume the data.

2 Likes

How do you expect to consume the data if you only have a reference to it? That's not possible.

2 Likes

Thanks to your comment, I found this.
https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#2803

#[stable(feature = "rust1", since = "1.0.0")]
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) -> Self::IntoIter {
        self.iter()
    }
}

Calling into_iter() over &Vec<T> actually returns just self.iter().
I was just confused because all basic examples showed calling into_iter() removed the variable.
Thank you ! :+1:

See this post by me for some more examples on Playground. It can feel a bit confusing indeed, but makes sense in my opinion. (Regarding the examples in the other post: providing no method is like invoking into_iter.)


An explicit into_iter (on the !Copy receiver, and where you have !Copy items) is needed when we need explicit conversion into an iterator (e.g. use it without a for loop), but don't want to retrieve references.

1 Like

I saw your great post. It was very helpful and I have one question.

    // These are equivalent if `r` is a `&Vec`:
    let r = &v;
    for x in r.iter() {
        println!("{x}")
    }
    for x in r {
        println!("{x}")
    }

    // `&Vec` implements `Copy`, so the previous loop didn't consume `r`:
    for x in r {
        println!("{x}")
    }

Here you mentioned that:

&Vec implements Copy, so the previous loop didn't consume r

Does that mean the x in the last (and previous) loop is a copied version of original vector elements?
If so, type of x should be i32 but rust-analyzer says x is &i32 type.
And also when I changed vector to have String elements which is not a copy type, it worked correctly.
Could you explain what I am misunderstanding?

No. The only thing that's copied is a reference to the vector.

3 Likes

The types in that example are:

  • v[0] and v[1] are i32, which implements Copy
  • v is a Vec<i32> which does not implement Copy and would require explicit cloning
  • r is a &Vec<i32> which does implement Copy (as all references implement Copy)
  • the type of x depends on the particular version of the loop

In this loop…

x is of type &i32, so it's a reference to the original vector element(s).

See the following example where the elements of the Vec are Strings, so being !Copy:

fn main() {
    let v: Vec<String> = vec!["Hello".to_string(), "World".to_string()];
    let r = &v;
    // now `r` is `Copy`, but
    // neither `v` nor `v[0]` (or `v[1]`) is `Copy`
    for s in r {
        let s: &String = s; // s is a `&String` here
        println!("{s}");
    }
    // we can repeat this because `r` is `Copy` and
    // wasn't consumed by the `for` statement
    for s in r {
        let s: &String = s; // s is a `&String` here
        println!("{s}");
    }
}

(Playground)

2 Likes

Thank you very much for your kind and detailed explanation.
Now It's very clear to me.
Extremely helpful. :+1: Thanks again !

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.