I have implemented a Cons list using a Box pointer to the next element in the list as follows.
#[derive(Debug, PartialEq, Eq)]
enum List<T> {
Cons(T, Box<List<T>>),
Nil,
}
impl<T: Copy> List<T> {
pub fn from_slice(v: &[T]) -> List<T> {
let mut inner = List::Nil;
for &next_elem in v.iter().rev() {
inner = List::Cons(next_elem, Box::new(inner));
}
inner
}
}
struct ListIter<'a, T>(&'a List<T>);
impl<'a, T> Iterator for ListIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
List::Cons(inner, next) => {
self.0 = next;
Some(inner)
},
List::Nil => None
}
}
}
This implementation works the way I want and has all the features I want. But is it possible to achieve the same functionality using a plain shared reference (&List) to represent a pointer to the next node in the List? For example such that List might defined as
#[derive(Debug, PartialEq, Eq)]
enum List<'a, T> {
Cons(T, &'a List<'a, T>),
Nil,
}
And if so, what are the costs and benefits of using a plain shared reference as opposed to a Box?
I tried my hand at it but I couldn't find a straightforward way to implement from_slice for List<'a, T> without violating the borrowing rules.
If I make a list
List::Cons(1, &List::Cons(2, &List::Nil)), I have a reference to that inner list&List::Cons(2, &List::Nil), right? That reference is to aListon the stack.That is to say,
List::Cons(1, &List::Cons(2, &List::Nil))is extremely similar toWhen I return from the function, no one owns the resulting stack values --
xandyare destroyed. Thus you can't returnz, it's referencing data that will no longer exist.