I have a relatively complex data structure (for reasons I don’t want to go into here).
It is defined as
pub struct VecData<T>(Rc<RefCell<Rc<Vec<T>>>>);
What I am looking for is a way to implement the IntoIter and Iterator traits for this struct. To be precise, I want to be able to iterate over the elements of type &T without cloning the inner Vec<T>.
>Solution :
You cannot do that, but you can come close, by yielding Ref<T> instead:
use std::cell::{Ref, RefCell};
use std::rc::Rc;
pub struct VecData<T>(Rc<RefCell<Rc<Vec<T>>>>);
impl<T> VecData<T> {
pub fn iter(&self) -> Iter<'_, T> {
Iter {
data: self.0.borrow(),
index: 0,
}
}
}
pub struct Iter<'a, T> {
data: Ref<'a, Rc<Vec<T>>>,
index: usize,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = Ref<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.data.len() {
return None;
}
let item = Ref::map(Ref::clone(&self.data), |data| &data[self.index]);
self.index += 1;
Some(item)
}
}
The reasoning you cannot do that is as follows: imagine you could do that, then you could create the iterator, extract the first item out of it then drop the iterator. Now you have a &T pointing to inside the Rc<Vec>, and no bookkeeping to inform the RefCell it is borrowed. Now you replace the inner Rc by borrow_mut()ing the RefCell. You got a dangling reference! Surely this has to be disallowed.