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

// 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));

我完全搞糊涂了——对于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 
where
    <Self::IntoIter as Iterator>::Item == Self::Item, 
{
    type Item;
    type IntoIter: Iterator;
    fn into_iter(self) -> Self::IntoIter;
}

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

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

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

每种变体略有不同.

这个函数消耗Vec及其迭代器yields values(直接消耗T):

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

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

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

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

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

所以:

iterinto_iter之间有什么区别?

into_iter是获取迭代器的通用方法,无论该迭代器生成值、不可变引用还是可变引用is context dependent,有时都会令人惊讶.

iteriter_mut是临时方法.因此,它们的返回类型独立于上下文,通常是迭代器,分别生成不可变引用和可变引用.

Rust by Example post的作者举例说明了对调用into_iter的上下文(即类型)的依赖所带来的惊喜,并利用以下事实使问题更加复杂:

  1. IntoIterator不执行[T; N],仅用于&[T; N]&mut [T; N],它将用于Rust 2021.
  2. 如果没有为某个值实现某个方法,则会自动搜索该值的references

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

数组实现了IntoIterator(以如此惊人的方式),从而可以在for个循环中迭代对它们的引用.

从Rust 1.51开始,数组可以实现一个迭代器来生成值(通过array::IntoIter),但现有的IntoIterator实现会自动引用makes it hard to implement by-value iteration via IntoIterator.

Rust相关问答推荐

将一个泛型类型转换为另一个泛型类型

如何创建一个可变的嵌套迭代器?

习语选项<;T>;到选项<;U>;当T->;U用From定义

为什么`tokio::main`可以直接使用而不需要任何导入?

为什么某些类型参数仅在特征边界中使用的代码在没有 PhantomData 的情况下进行编译?

将泛型中的 Box 转换为 rust 中的 Box

Button.set_hexpand(false) 不会阻止按钮展开

Rust 中的自动取消引用是如何工作的?

如何在 Rust 的 Hyper 异步闭包中从外部范围正确读取字符串值

Rust Serde 为 Option:: 创建反序列化器

我的 Axum 处理程序无法编译:未实现 IntoResponse 特征

更好的方法来模式匹配带有 Rust 的窥视孔装配说明窗口?

If let expression within .iter().any

`use std::error::Error` 声明中断编译

我如何将特征作为 struct 的拥有字段?

火箭整流罩、tokio-scheduler 和 cron 的生命周期问题

如何制作具有关联类型的特征的类型擦除版本?

如何通过查看 windows 计算机确定要编译到哪个 rust 目标?

如何记录错误并返回/继续结果/选项

带有不安全 rust 的链表泄漏内存