如何在Rust中为特定集合类型(列表/集合/地图)创建一个空的迭代器?

Nik*_*lai 7 iterator rust

我想编写一个返回集合迭代器(例如 LinkedList)的方法。但是在某些情况下,没有合适的集合可以返回迭代器。在这种情况下,我想返回一个“空”迭代器,该迭代器不对任何元素进行迭代。但是,我找不到任何相关的功能构建linked_list::Iter的文档

考虑以下示例:

use std::collections::HashMap;
use std::collections::LinkedList;
use std::collections::linked_list;

pub struct Graph {
    nodes: HashMap<usize, LinkedList<usize>>,
}

impl Graph {
    pub fn adjacent_nodes(&self, node: usize) -> linked_list::Iter<usize> {
        match self.nodes.get(&node) {
            Some(x) => x.iter(),
            _ => linked_list::Iter::<usize>::new()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想从该adjacent_nodes 方法的相邻节点上返回一个迭代器。但是,当要求一个不存在的节点的邻居时,该方法显然应该返回一无所有的迭代器。但是我怎么创建它呢?我提供的代码实际上无法编译:

src/graph.rs:13:18: 13:49 error: no associated item named `new` found for type
        `collections::linked_list::Iter<'_, usize>` in the current scope
src/graph.rs:13             _ => linked_list::Iter::<usize>::new()
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我猜想,我可以解决此问题,boxed::Box但由于我试图避免不必要的堆分配,显然这不是次优的解决方案。

所以,我的问题是:在Rust中是否可以创建特定类型的迭代器?

Vla*_*eev 8

您不能这样做,不能使用按引用迭代器,因为它们总是与具体的集合实例相关联。

您可以做的是将装箱迭代器作为特征对象返回:

pub fn adjacent_nodes<'a>(&'a self, node: usize) -> Box<Iterator<Item=usize>+'a> {
    match self.nodes.get(&node) {
        Some(x) => Box::new(x.iter()),
        _ => Box::new(::std::iter::empty())
    }
}
Run Code Online (Sandbox Code Playgroud)

std::iter::empty()返回一个空的迭代器,但当然它的类型与集合迭代器的类型不同,所以你必须使用一个 trait 对象。我还必须添加一个生命周期参数,因为 返回的迭代器iter()绑定到self.nodes,您需要向编译器解释它。

  • 感谢你的回答。但我不太明白为什么空迭代器必须绑定到具体的集合实例。在我看来,这就像标准库中的一个缺陷。像这样不必要的堆分配当然不是零成本抽象。 (3认同)
  • @Nikolai,空迭代器和非空迭代器没有区别。重要的是迭代器类型。`Iterator` 是一个 trait,并且有实现这个 trait 的类型。每个集合都有自己的迭代器类型,因为数据结构不同,迭代器必须了解集合的实现。因此,不同集合的迭代器是不兼容的。当迭代器产生引用时会出现更多问题,因为它们通过类型中的生命周期参数绑定到集合。 (3认同)
  • 如果您需要该特定类型。切片迭代器是一个例外:`[].iter()` 和 `[].iter_mut()` 都应该没问题。 (2认同)