如何编写一个简单地反转迭代的自定义 `IntoIterator` 实现?

问题描述

我是 Rust 新手,我正在尝试实现具有 struct自定义 Vec。我希望这个自定义结构是可迭代的,并且以相反的顺序在内部 Vec 上迭代。

到目前为止,我所理解的是我需要实现 IntoIterator 特征,并最终实现一个自定义 IteratorIntoIterator自定义结构转换为该自定义结构。由于我只想反转 Vec 上的迭代,因此我想重新使用标准库已经提供的内容

这是我的结构:

pub struct BitMap {
    content: Vec<u64>,}

这就是我尝试实现 IntoIterator 的方式:

impl<'a> iter::IntoIterator for &'a BitMap {
    type Item = u64;
    type IntoIter = iter::Rev<slice::Iter<'a,Self::Item>>;

    fn into_iter(self) -> Self::IntoIter {
        (&(self.content)).iter().rev()
    }
}

但是编译器抱怨:

47  |     type IntoIter = iter::Rev<slice::Iter<'a,Self::Item>>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`,found reference

我正在努力理解如何实现这件简单的事情。

更新

感谢E_net4 says don't copy thatanswer

考虑到您提到您的解决方案需要复制元素,我尝试实现一个试图避免它的版本,这就是我想出的:

impl<'a> iter::IntoIterator for &'a BitMap {
    type Item = u64;
    type IntoIter = BitMapIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        BitMapIterator::new(&self.content)
    }
}

pub struct BitMapIterator<'a> {
    content: &'a Vec<u64>,index: usize,}

impl<'a> BitMapIterator<'a> {
    fn new(content: &'a Vec<u64>) -> Self {
        BitMapIterator {
            content,index: content.len(),}
    }
}

impl iter::Iterator for BitMapIterator<'_> {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index == 0 {
            None
        } else {
            self.index -= 1;
            Some(self.content[self.index])
        }
    }
}

但是正如你所看到的,这需要我实现一个自定义的迭代器并将其公开。这似乎是我想要的,如果我在不复制元素的情况下正确理解,但我不知道这个解决方案是多么地道,它基本上不重用 std lib 提供的任何东西。

解决方法

在向量上调用 .iter() 会创建一个非拥有项的迭代器,它将位于不可变引用之后。并且 &u64 个项目的迭代器不能履行 u64 个项目的迭代器的角色。

考虑到 u64 的复制成本很低,用 .copied 修改迭代器就足以获得返回实际值的迭代器。复制的迭代器是惰性的,它只在遍历项目时复制它们。

use std::{iter,slice};

pub struct BitMap {
    content: Vec<u64>,}

impl<'a> iter::IntoIterator for &'a BitMap {
    type Item = u64;
    type IntoIter = iter::Copied<iter::Rev<slice::Iter<'a,Self::Item>>>;

    fn into_iter(self) -> Self::IntoIter {
        self.content.iter().rev().copied()
    }
}

Playground

另见: