Я нашел способ сделать это:
Объяснение
Я понял, что хотел бы, чтобы Index
предоставил метод enumerate
для перечисления индексов и элементов, стоящих за индексом коллекции. Таким образом, с помощью принятого ответа Использование универсальных итераторов вместо определенных типов списков Я реализовал супертрейт 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: определить супертрейт для Index
, который добавляет метод enumerate
/// 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: Внедрить супертрейт дляколлекции, которые я хочу использовать
Реализация для 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
для каждой коллекции. - InВ каждой реализации мы должны убедиться, что два итератора упорядочены последовательно.
Если что-то не так в моей реализации, пожалуйста, дайте мне знать! Кажется, работает нормально, но я понимаю только половину того, что я делаю.