假设我有一个IntoIter,我想从右到左收集n个元素的块(相当于切片上的rchunk).我可以在迭代器上调用.rev(),然后为我想要收集的每个块调用.by_ref().take(n).rev().

let mut iter = vec![vec![0], vec![1], vec![2], vec![3]]
    .into_iter()
    .rev();

let vec1: Vec<_> = iter.by_ref().take(2).rev().collect();
println!("{:?}", vec1);

let vec2: Vec<_> = iter.by_ref().take(2).rev().collect();
println!("{:?}", vec2);

这适用于vec1,但vec2将为空.

我认为vec2应该是[[0],[1]],而不是空的.看起来.rev()方法不仅更改了Take迭代器,还更改了原始迭代器.它是在消耗原始迭代器,还是正在发生什么?

推荐答案

您和其他许多人一样,误解了takerev和其他迭代器适配器的工作方式.他们不坐/倒/...直接,相反,它们包装底层迭代器并返回一个新的迭代器,该迭代器的行为就像它只有2个长/从另一端迭代/...因此,从左侧开始迭代.rev() … chain of adapters … .rev()ed迭代器,因此.rev().take(n).rev()的适配器链确实遍历了all个元素,并且只保留最后n个元素,因为最后rev()个元素将next()个调用转换为next_back() of the DoubleEndedIterator implementation of Take个 ,它跳到第一个被获取的元素

self.iter.nth_back(self.iter.len().saturating_sub(n))

为了达到所需的效果,您必须将迭代器再次反转到collect() before:

fn main() {
    let mut iter = vec![vec![0], vec![1], vec![2], vec![3]].into_iter().rev();

    let vec1 = {
        let mut r = Vec::from_iter(iter.by_ref().take(2));
        r.reverse();
        r
    };
    println!("{:?}", vec1);

    let vec2 = {
        let mut r = Vec::from_iter(iter.by_ref().take(2));
        r.reverse();
        r
    };
    println!("{:?}", vec2);
}

Rust相关问答推荐

如何初始化match声明中的两个变量而不会激怒borrow 判断器?

空字符串转换为Box字符串时是否分配?<>

如何使用字符串迭代器执行查找?

如何在Tauri中将变量从后端传递到前端

编译项目期间使用Cargo生成时出现rustc错误

Rust中WPARAM和VIRTUAL_KEY的比较

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

为什么rustc会自动降级其版本?

为什么AsyncRead在Box上的实现有一个Unpin特征绑定?

为什么在 Allocator API 中 allocate() 使用 `[u8]` 而 deallocate 使用 `u8` ?

详尽的匹配模式绑定

可选包装枚举的反序列化

Rust 中指向自身的引用如何工作?

str 和 String 的 Rust 生命周期

Rust:`sort_by` 多个条件,冗长的模式匹配

如何将这些测试放在一个单独的文件中?

打印 `format_args!` 时borrow 时临时值丢失

为什么 Rust 编译器在移动不可变值时执行复制?

深度嵌套枚举的清洁匹配臂

在 Rust 中获得准确时间的正确方法?