What is the difference between iter and into_iter?
Asked Answered
S

6

477

I am doing the Rust by Example tutorial, which has this code snippet:

// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];

// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter()     .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));

// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];

// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter()     .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));

I am quite confused — for a Vec, the iterator returned from .iter yields references and the iterator returned from .into_iter yields values, but for an array these iterators are identical?

What is the use case/API for these two methods?

Sarto answered 12/1, 2016 at 0:48 Comment(0)
S
484

TL;DR:

  • The iterator returned by into_iter may yield any of T, &T or &mut T, depending on the context.
  • The iterator returned by iter will yield &T, by convention.
  • The iterator returned by iter_mut will yield &mut T, by convention.

The first question is: "What is into_iter?"

into_iter comes from the IntoIterator trait:

pub trait IntoIterator 
where
    <Self::IntoIter as Iterator>::Item == Self::Item, 
{
    type Item;
    type IntoIter: Iterator;
    fn into_iter(self) -> Self::IntoIter;
}

You implement this trait when you want to specify how a particular type is to be converted into an iterator. Most notably, if a type implements IntoIterator it can be used in a for loop.

For example, Vec implements IntoIterator... thrice!

impl<T> IntoIterator for Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>
impl<'a, T> IntoIterator for &'a mut Vec<T>

Each variant is slightly different.

This one consumes the Vec and its iterator yields values (T directly):

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

    fn into_iter(mut self) -> IntoIter<T> { /* ... */ }
}

The other two take the vector by reference (don't be fooled by the signature of into_iter(self) because self is a reference in both cases) and their iterators will produce references to the elements inside Vec.

This one yields immutable references:

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

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

While this one yields mutable references:

impl<'a, T> IntoIterator for &'a mut Vec<T> {
    type Item = &'a mut T;
    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ }
}

So:

What is the difference between iter and into_iter?

into_iter is a generic method to obtain an iterator, whether this iterator yields values, immutable references or mutable references is context dependent and can sometimes be surprising.

iter and iter_mut are ad-hoc methods. Their return type is therefore independent of the context, and will conventionally be iterators yielding immutable references and mutable references, respectively.

The author of the Rust by Example post illustrates the surprise coming from the dependence on the context (i.e., the type) on which into_iter is called, and is also compounding the problem by using the fact that:

  1. IntoIterator is not implemented for [T; N], only for &[T; N] and &mut [T; N] -- it will be for Rust 2021.
  2. When a method is not implemented for a value, it is automatically searched for references to that value instead

which is very surprising for into_iter since all types (except [T; N]) implement it for all 3 variations (value and references).

Arrays implement IntoIterator (in such a surprising fashion) to make it possible to iterate over references to them in for loops.

As of Rust 1.51, it's possible for the array to implement an iterator that yields values (via array::IntoIter), but the existing implementation of IntoIterator that automatically references makes it hard to implement by-value iteration via IntoIterator.

Sinusitis answered 12/1, 2016 at 14:8 Comment(11)
I found this blog post helpful: hermanradtke.com/2015/06/22/…Sequent
>whether this iterator yields values, immutable references or mutable references is context dependent What does it mean and how to deal with that? How one would force iter_mut to yield mutable values, for example?Motoring
@DanM.: (1) It means that into_iter picks an implementation based on whether the receiver is a value, reference or mutable reference. (2) There are no mutable values in Rust, or rather, any value is mutable since you have ownership.Sinusitis
@MatthieuM.hm, that doesn't seem to be the case in my tests. I've implemented IntoIter for &'a MyStruct and &mut 'a MyStruct and the first one was always chosen if present even if I called into_iter().for_each() on mut value with &mut arguments in lambda.Motoring
@DanM.: This seems strange to me; I would suggest posting a question with a minimal reproducible example reproducing this.Sinusitis
@MatthieuM. ok, but just to be sure, this is not the expected behavior, is it?Motoring
@DanM.: It seems like a limitation of the type-inference/trait-selection mechanism to me, I'd still ask the question explicitly on SO with this example to see if there's a specific language rule for the behavior, or any work on improving things. It's notable that were you to use a for loop you'd need to write &mut foo too.Sinusitis
For arrays implementing IntoIter, see also github.com/rust-lang/rust/issues/65798.Condon
I found this blog post helpful too, xion.io/post/code/rust-for-loop.htmlTruong
Worth noting that arrays will implement IntoIter in rust 2021 edition, and they plan to backport it so it mostly works in all editions: blog.rust-lang.org/2021/05/11/edition-2021.htmlBrewis
For the people who are curious about 2. When a method is not implemented for a value, it is automatically searched for references to that value instead, check this out.Scuttle
B
356

I came here from Google seeking a simple answer which wasn't provided by the other answers. Here's that simple answer:

  • iter() iterates over the items by reference
  • iter_mut() iterates over the items, giving a mutable reference to each item
  • into_iter() iterates over the items, moving them into the new scope

So for x in my_vec { ... } is essentially equivalent to my_vec.into_iter().for_each(|x| ... ) - both move the elements of my_vec into the ... scope.

If you just need to look at the data, use iter, if you need to edit/mutate it, use iter_mut, and if you need to give it a new owner, use into_iter.

This was helpful: http://hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html

Brocatel answered 12/1, 2016 at 0:49 Comment(2)
This is the good simple answer for the (common?) case where my_vec or whatever you are calling .into_iter() on is in fact a Vec<T>. The other answers are more complicated to also mention that, if you call .into_iter() on other things such as a &Vec<T> or &[] (or equivalently, try to iterate over them in a for ... in ... loop), you might not actually be moving the items into the new scope. (At least, that's my understanding so far...)Frances
Yeah, "into_iter() iterates over the items, moving them into the new scope" is not always accurate - see the accepted answer for more details.Pericarditis
E
24

I think there's something to clarify a bit more. Collection types, such as Vec<T> and VecDeque<T>, have into_iter method that yields T because they implement IntoIterator<Item=T>. There's nothing to stop us to create a type Foo<T> if which is iterated over, it will yield not T but another type U. That is, Foo<T> implements IntoIterator<Item=U>.

In fact, there are some examples in std: &Path implements IntoIterator<Item=&OsStr> and &UnixListener implements IntoIterator<Item=Result<UnixStream>>.


The difference between into_iter and iter

Back to the original question on the difference between into_iter and iter. Similar to what others have pointed out, the difference is that into_iter is a required method of IntoIterator which can yield any type specified in IntoIterator::Item. Typically, if a type implements IntoIterator<Item=I>, by convention it has also two ad-hoc methods: iter and iter_mut which yield &I and &mut I, respectively.

What it implies is that we can create a function that receives a type that has into_iter method (i.e. it is an iterable) by using a trait bound:

fn process_iterable<I: IntoIterator>(iterable: I) {
    for item in iterable {
        // ...
    }
}

However, we can't* use a trait bound to require a type to have iter method or iter_mut method, because they're just conventions. We can say that into_iter is more widely useable than iter or iter_mut.

Alternatives to iter and iter_mut

Another interesting thing to observe is that iter is not the only way to get an iterator that yields &T. By convention (again), collection types SomeCollection<T> in std which have iter method also have their immutable reference types &SomeCollection<T> implement IntoIterator<Item=&T>. For example, &Vec<T> implements IntoIterator<Item=&T>, so it enables us to iterate over &Vec<T>:

let v = vec![1, 2];

// Below is equivalent to: `for item in v.iter() {`
for item in &v {
    println!("{}", item);
}

If v.iter() is equivalent to &v in that both implement IntoIterator<Item=&T>, why then does Rust provide both? It's for ergonomics. In for loops, it's a bit more concise to use &v than v.iter(); but in other cases, v.iter() is a lot clearer than (&v).into_iter():

let v = vec![1, 2];

let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();

Similarly, in for loops, v.iter_mut() can be replaced with &mut v:

let mut v = vec![1, 2];

// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
    *item *= 2;
}

When to provide (implement) into_iter and iter methods for a type

If the type has only one “way” to be iterated over, we should implement both. However, if there are two ways or more it can be iterated over, we should instead provide an ad-hoc method for each way.

For example, String provides neither into_iter nor iter because there are two ways to iterate it: to iterate its representation in bytes or to iterate its representation in characters. Instead, it provides two methods: bytes for iterating the bytes and chars for iterating the characters, as alternatives to iter method.


* Well, technically we can do it by creating a trait. But then we need to impl that trait for each type we want to use. Meanwhile, many types in std already implement IntoIterator.

Exsanguinate answered 11/7, 2020 at 11:39 Comment(0)
S
9

.into_iter() is not implemented for a array itself, but only &[]. Compare:

impl<'a, T> IntoIterator for &'a [T]
    type Item = &'a T

with

impl<T> IntoIterator for Vec<T>
    type Item = T

Since IntoIterator is defined only on &[T], the slice itself cannot be dropped the same way as Vec when you use the values. (values cannot be moved out)

Now, why that's the case is a different issues, and I'd like to learn myself. Speculating: array is the data itself, slice is only a view into it. In practice you cannot move the array as a value into another function, just pass a view of it, so you cannot consume it there either.

Saccharoid answered 12/1, 2016 at 1:2 Comment(8)
IntoIterator is also implemented for &'a mut [T], so it could move the objects out of the array. I think that it is related to the fact that the return struct IntoIter<T> does not have a lifetime argument while Iter<'a, T> does, so the former cannot hold a slice.Brown
mut means that you can change the values, not that you can move them out.Saccharoid
@Brown let mut a = ["abc".to_string()]; a.into_iter().map(|x| { *x }); => "error: cannot move out of borrowed content"Saccharoid
Yeah, I think you are right and values cannot be moved from the array. However, I still think that it should be possible to implement a kind of ArrayIntoIter struct using unsafe Rust, as part of the library... Maybe not worth it, as you should use Vec for those cases anyway.Brown
so I don't understand... is that the reason that array.into_iter returns &T - because it is doing magic to automatically convert it to &array.into_iter -- and if so, I don't understand what that has to do with moving values or not moving values. Or is it as @Brown said, that you get the reference simply because (for some reason) you cannot move values out of arrays? Still very confused.Sarto
related: what does "moving" mean under the covers? I was under the impression that it meant that it literally "moves" the data (for instance from the stack to the heap). Also, is "moving" the same thing as getting something "by value"?Sarto
So one by one: Yes, into_iter returns &T, because you're really calling &array.into_iter(). This is not really magical - it happens automatically for all methods (needed & will be added automatically). Not being able to move the array was just a side comment that's slightly related; it may or may not explain the answer. Moving the value means it is not valid in the previous location anymore and is instead present in the new one. This happens for vec2 for example. At the end of this code, you can access vec1[0], but not vec2[0].Saccharoid
@Brown that IntoIterator is implemented for &mut [T] does not imply that it is possible to move objects out of an array. It is not possible: all array items must always be initialized in Rust, and the only way to move something out of a (mutable) slice is to use std:::mem::replace() and similar functions. Also, because Rust does not have type-level integers yet, it is not possible to write an implementation of by-value IntoIterator for arrays - you'd need a separate implementation for every array size, which without type-level integers is absolutely unwieldy.Newmodel
T
2

IntoIterator and Iterator are usually used like this.

We implement IntoIterator for structures that has an inner/nested value (or is behind a reference) that either implements Iterator or has an intermediate "Iter" structure.

For example, lets create a "new" data structure:

struct List<T>; 
// Looks something like this:
// - List<T>(Option<Box<ListCell<T>>>)
// - ListCell<T> { value: T, next: List<T> }

We want this List<T> to be iterable, so this should be a good place to implement Iterator right? Yes, we could do that, but that would limit us in certain ways.

Instead we create an intermediate "iterable" structure and implement the Iterator trait:

// NOTE: I have removed all lifetimes to make it less messy.
struct ListIter<T> { cursor: &List<T> };
impl<T> Iterator for ListIter<T> {
  type Item = &T;
  fn next(&mut self) -> Option<Self::Item> {...}
}

So now we need to somehow connect List<T> and ListIter<T>. This can be done by implementing IntoIterator for List.

impl<T> IntoIterator for List<T> {
    type Item = T;
    type Iter = ListIter<Self::Item>; 
    fn into_iter(self) -> Self::Iter { ListIter { cursor: &self } }
}

IntoIterator can also be implemented multiple times for container struct if for example it contains different nested iterable fields or we have some higher kinded type situation.

Lets say we have a Collection<T>: IntoIterator trait that will be implemented by multiple data structures, e.g. List<T>, Vector<T> and Tree<T> that also have their respective Iter; ListIter<T>, VectorIter<T> and TreeIter<T>. But what does this actually mean when we go from generic to specific code?

fn wrapper<C>(value: C) where C: Collection<i32> {
  let iter = value.into_iter() // But what iterator are we?
  ...
}

This code is not 100% correct, lifetimes and mutability support are omitted.

Teide answered 20/11, 2022 at 0:28 Comment(0)
D
2

I found very simple and clear example code,

Items in an iterator made with

  • iter will be a reference
  • into_iter will be an owned value
  • iter_mut will be a mutable reference
#[test]
fn iter_demo() {
    let v1 = vec![1, 2, 3];
    let mut v1_iter = v1.iter();

    // iter() returns an iterator of slices.
    assert_eq!(v1_iter.next(), Some(&1));
    assert_eq!(v1_iter.next(), Some(&2));
    assert_eq!(v1_iter.next(), Some(&3));
    assert_eq!(v1_iter.next(), None);
}

#[test]
fn into_iter_demo() {
    let v1 = vec![1, 2, 3];
    let mut v1_iter = v1.into_iter();

    // into_iter() returns an iterator from a value.
    assert_eq!(v1_iter.next(), Some(1));
    assert_eq!(v1_iter.next(), Some(2));
    assert_eq!(v1_iter.next(), Some(3));
    assert_eq!(v1_iter.next(), None);
}

#[test]
fn iter_mut_demo() {
    let mut v1 = vec![1, 2, 3];
    let mut v1_iter = v1.iter_mut();

    // iter_mut() returns an iterator that allows modifying each value.
    assert_eq!(v1_iter.next(), Some(&mut 1));
    assert_eq!(v1_iter.next(), Some(&mut 2));
    assert_eq!(v1_iter.next(), Some(&mut 3));
    assert_eq!(v1_iter.next(), None);
}

https://gist.github.com/philipjkim/98bc460d31773255fd2b20780a73b742

Doenitz answered 18/2, 2024 at 2:24 Comment(1)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewLivre

© 2022 - 2025 — McMap. All rights reserved.