gpt4 book ai didi

generics - 如何迭代实现 Index 和 IntoIterator 的通用集合的索引?

转载 作者:行者123 更新时间:2023-11-29 08:19:46 24 4
gpt4 key购买 nike

我想为任何通用集合实现一个小的有向图特征 C实现 std::ops::Indexstd::iter::IntoIterator .我希望集合代表图形的节点。每个节点都由其在 C 中的索引表示,这可能是一个 usize索引到 VecString键入 HashMap .我不知道这是否是图形库的最佳方法,但我也想了解 Rust、泛型特征和 Rust 的标准库。

在我实现的某些点上,我需要遍历 C 的所有索引实例。我找到的唯一方法是 enumerate函数,但这只实现了一个 usize迭代器的计数器而不是我的通用类型,所以它适用于 Vec , 但不适用于 HashMap .

这是使用 enumerate 实现的样子. nodeschildren需要功能,children返回图的邻接信息。使用 parents 获取所有前辈函数,我需要迭代通用容器类型的索引。

pub trait SimpleGraph {
/// type used as an index to refer to nodes.
type I: Eq + std::hash::Hash;

/// container type for the nodes
type C: std::ops::Index<Self::I> + std::iter::IntoIterator<Item = Self::I>;

/// returns a reference to the node container.
fn nodes(&self) -> &Self::C;

/// gets the indices of the children of a node with index `index`.
fn children(&self, index: Self::I) -> Vec<Self::I>;

/// gets all ancestors of a node (not very efficient...)
fn parents(&self, i: Self::I) -> Vec<Self::I> {
let mut res = Vec::<Self::I>::new();
let nodes = self.nodes();
for (idx, _) in nodes.into_iter().enumerate() {
let children = self.children(idx);
for child_idx in children {
if child_idx == i {
res.push(idx);
}
}
}
return res;
}
}

这给了我一个不太令人惊讶的编译器错误:

error[E0308]: mismatched types
--> src/lib.rs:19:42
|
19 | let children = self.children(idx);
| ^^^ expected associated type, found usize
|
= note: expected type `<Self as SimpleGraph>::I`
found type `usize`

一个丑陋的解决方案是添加另一个必需的方法indices它返回一个索引列表,然后遍历这个列表,但这对用户来说不是很友好,而且对于 std::collections 中的任何一个来说似乎都是不必要的步骤。实现了 std::ops::Indexstd::iter::IntoIterator .我宁愿覆盖 enumerate以通用方式发挥作用。

我如何以一种干净和通用的方式对此进行编码?

最佳答案

我找到了一种方法:

说明

我意识到我希望 Index 提供一个 enumerate 方法来枚举索引和集合索引后面的项目。所以在接受的答案的帮助下 Using generic iterators instead of specific list types我实现了提供此方法的 Index 超特征。

第 1 步:定义一个新的 Enumerate 结构并为其实现 Iterator

pub struct Enumerate<IndexIter, ItemIter> {
index: IndexIter,
item: ItemIter,
}

/// implements the [`Iterator`] trait for the new struct
impl<IndexIter, ItemIter> Iterator for Enumerate<IndexIter, ItemIter>
where
IndexIter: Iterator,
ItemIter: Iterator,
{
type Item = (IndexIter::Item, ItemIter::Item);

/// returns the next iterator
#[inline]
fn next(&mut self) -> Option<(IndexIter::Item, ItemIter::Item)> {
self.index.next().map(|idx| {
// CAUTION! We need to make sure that the index and item iterators are ordered consistently.
// We are really just incrementing two iterators simultaneously here...
(idx, self.item.next().unwrap())
})
}
}

第 2 步:为添加 enumerate 方法的 Index 定义一个超特征

/// trait for implementing over the indices of collections that implement [`std::ops::Index`].
///
/// It adds the enumerate function that returns an `Enumerate<IndexIter,ItemIter>` as an iterator.
pub trait SuperIndex<'a, Idx>: std::ops::Index<Idx> {
type IndexIter: Iterator<Item = Idx>;
type ItemIter: Iterator;

/// enumerates over the indices and items of a collection
fn enumerate(&'a self) -> Enumerate<Self::IndexIter, Self::ItemIter>;
}

第 3 步:为我要使用的集合实现 super 特征

Vec的实现

/// implement the [`SuperIndex`] trait for [`Vec<T>`]
impl<'a, T: 'a> SuperIndex<'a, usize> for Vec<T> {
type IndexIter = std::ops::Range<usize>;
type ItemIter = std::slice::Iter<'a, T>;

fn enumerate(&'a self) -> Enumerate<Self::IndexIter, Self::ItemIter> {
Enumerate {
index: 0..self.len(),
item: self.iter(),
}
}
}

HashMap的实现

/// implement the [`SuperIndex`] trait for [`HashMap<K, V, S>`]
impl<'a, K: 'a, V: 'a, S> SuperIndex<'a, &'a K> for std::collections::HashMap<K, V, S>
where
K: Eq + std::hash::Hash,
S: std::hash::BuildHasher,
{
type IndexIter = std::collections::hash_map::Keys<'a, K, V>;
type ItemIter = std::collections::hash_map::Values<'a, K, V>;

fn enumerate(&'a self) -> Enumerate<Self::IndexIter, Self::ItemIter> {
Enumerate {
index: self.keys(),
item: self.values(),
}
}
}

讨论

现在我可以为实现 SuperIndex 的任何类型的集合枚举索引和值,并且 index 不必是 usize:

for (index, item) in c.enumerate() {
assert_eq!(&c[index], item);
}

这个实现做了我想要的,我想不出任何替代方案,但它有一些小缺陷:

  • SuperIndex 索引不能像 Index 那样通用,例如不允许切片。
  • 我们需要为每个集合显式实现 SuperIndex
  • 在每个实现中,我们必须确保两个迭代器的顺序一致。

如果我的实现有任何问题,请告诉我!它似乎工作正常,但我只了解我在做什么。

关于generics - 如何迭代实现 Index 和 IntoIterator 的通用集合的索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58260663/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com