Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between iter and into_iter?

Tags:

rust

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 thoroughly 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?

like image 951
vitiral Avatar asked Jan 12 '16 00:01

vitiral


People also ask

What is Into_iter rust?

iter_mut() provides iteration over mutable references ( &mut T ). into_iter() allows for iteration over any of the moved values ( T ), immutable references, or mutable references. In addition, it is also implicitly called (when possible) when using a for loop to iterate the collection.

What is Iter_mut in Rust?

iter_mut(); // We change the value of the first element of the slice returned by the `next` method: *iter. next(). unwrap() += 1; } // Now slice is "[2, 2, 3]": println!("


2 Answers

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.

like image 136
Matthieu M. Avatar answered Oct 16 '22 18:10

Matthieu M.


I (a Rust newbie) 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

Making this a community wiki so that hopefully a Rust pro can edit this answer if I've made any mistakes.

like image 30
2 revs, 2 users 92% Avatar answered Oct 16 '22 19:10

2 revs, 2 users 92%