iter 和 into_iter 有什么区别? [英] What is the difference between iter and into_iter?

查看:77
本文介绍了iter 和 into_iter 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做 Rust by Example 教程,其中包含以下代码片段:

//Vec 示例让 vec1 = vec![1, 2, 3];让 vec2 = vec![4, 5, 6];//vecs 的 `iter()` 产生 `&i32`.解构为`i32`.println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));//vecs 的 `into_iter()` 产生 `i32`.不需要解构.println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));//数组示例让数组 1 = [1, 2, 3];让数组 2 = [4, 5, 6];//数组的 `iter()` 产生 `&i32`.println!("2 in array1: {}", array1.iter() .any(|&x| x == 2));//数组的 `into_iter()` 异常产生 `&i32`.println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));

我很困惑 — 对于 Vec,从 iter 返回的迭代器产生引用,而从 into_iter 返回的迭代器产生值,但是对于这些迭代器是相同的数组吗?

这两种方法的用例/API 是什么?

解决方案

TL;DR:

  • into_iter 返回的迭代器可能产生 T&T&mut T 中的任何一个, 取决于上下文.
  • 按照约定,iter 返回的迭代器将产生 &T.
  • 按照约定,iter_mut 返回的迭代器将产生 &mut T.

第一个问题是:什么是into_iter?"

into_iter 来自 IntoIterator trait:

<块引用>

pub trait IntoIterator在哪里<Self::IntoIter 作为迭代器>::Item == Self::Item,{类型项目;类型 IntoIter:迭代器;fn into_iter(self) ->Self::IntoIter;}

当您想要指定如何将特定类型转换为迭代器时,您可以实现此特征.最值得注意的是,如果一个类型实现了 IntoIterator,它可以在 for 循环中使用.

例如,Vec 实现了 IntoIterator...三次!

<块引用>

impl;用于 Vec<T> 的 IntoIteratorimpl'a,T>&'a Vec<T>的IntoIteratorimpl'a,T>IntoIterator for &'a mut Vec<T>

每个变体都略有不同.

这个使用 Vec 及其迭代器 产生(直接T):

<块引用>

impl用于 Vec<T> 的 IntoIterator{类型项目 = T;输入 IntoIter = IntoIter;fn into_iter(mut self) ->IntoIter<T>{/* ... */}}

另外两个通过引用获取向量(不要被 into_iter(self) 的签名所迷惑,因为 self 在这两种情况下都是一个引用)和他们的迭代器将产生对 Vec 中元素的引用.

这个产生不可变引用:

<块引用>

impl<'a, T>&'a Vec<T>的IntoIterator{输入 Item = &'a T;type IntoIter = slice::Iter<'a, T>;fn into_iter(self) ->slice::Iter<'a, T>{/* ... */}}

虽然这个 产生可变的参考资料:

<块引用>

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>{/* ... */}}


所以:

<块引用>

iterinto_iter 有什么区别?

into_iter 是获取迭代器的通用方法,无论该迭代器产生值、不可变引用还是可变引用取决于上下文,有时可能会令人惊讶.

iteriter_mut 是临时方法.因此,它们的返回类型与上下文无关,并且通常是分别产生不可变引用和可变引用的迭代器.

Rust by Example 帖子的作者说明了对调用 into_iter 的上下文(即类型)的依赖所带来的惊喜,并且还通过使用事实使问题复杂化那个:

  1. IntoIterator 没有为 [T; 实现;N],仅用于 &[T;N]&mut [T;N] -- 它将用于 Rust 2021.
  2. 当一个方法没有为一个值实现时,它会自动搜索引用到那个值

这对于 into_iter 来说非常令人惊讶,因为所有类型([T; N] 除外)都为所有 3 种变体(值和引用)实现了它.

数组实现了 IntoIterator(以一种令人惊讶的方式),以便在 for 循环中迭代对它们的引用.

从 Rust 1.51 开始,数组可以实现一个产生值的迭代器(通过 array::IntoIter),但是自动引用 使得通过IntoIterator难以实现按值迭代.

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?

解决方案

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.

这篇关于iter 和 into_iter 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆