What is the difference between iter and into_iter?

匿名 (未验证) 提交于 2019-12-03 01:23:02

问题:

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?

回答1:

The first question is: "What is into_iter?"

into_iter comes from the IntoIterator trait:

pub trait IntoIterator  where     <: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 IntoIterator for Vec impl IntoIterator for &'a Vec impl IntoIterator for &'a mut Vec

Each variant is slightly different.

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

impl IntoIterator for Vec {     type Item = T;     type IntoIter = IntoIter;      fn into_iter(mut self) -> IntoIter { /* ... */ } } 

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 IntoIterator for &'a Vec {     type Item = &'a T;     type IntoIter = slice::Iter;      fn into_iter(self) -> slice::Iter { /* ... */ } } 

While this one yields mutable references:

impl IntoIterator for &'a mut Vec {     type Item = &'a mut T;     type IntoIter = slice::IterMut;      fn into_iter(self) -> slice::IterMut { /* ... */ } } 

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. This works around the context-dependent bit and, by convention, let you obtain an iterator which will yield references.

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]
  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). It's not possible for the array to implement an iterator that yields values because it cannot "shrink" to give up its items.

As to why arrays implement IntoIterator (in such a surprising fashion): it's to make it possible to iterate over references to them in for loops.



回答2:

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

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

with

impl IntoIterator for Vec     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.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!