Hi!
When trying to port some existing code, and at the same time learn more about the Rust idioms, I've run into the question on how to best setup a Parent
instance where i can iterate over its children, giving out a &Child
in each iteration.
I've broken this down to three questions: the two first related to why my Vec<Child>
approach doesnt work, and if it somehow can be made to. The third question is about advantages/disadvantages when using &Vec<Child>
or Vec<&Child>
.
Thanks in advance!
First try: children as Vec<Child>
My first naive approach was storing the children as Vec<Child>
, but that doesn't seem to work - the compiler is complaining about missing explicit lifetime for the iterator type Item = &Child
:
#[derive(Debug)]
pub struct Parent1 {
children: Vec<Child>,
idx: usize,
}
impl Parent1 {
fn new(children: Vec<Child>) -> Self {
Self { children, idx: 0 }
}
}
impl Iterator for Parent1 {
type Item = &Child; // <---- explicit lifetime needed here
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.children.len() {
let item = &self.children[self.idx];
self.idx += 1;
return Some(item);
}
None
}
}
Question 1: Why is that so? Couldn't the compiler figure out that the &child references should live as long as the Parent instance and it's children vec?
Question 2: Is there a way to actually notate the lifetime in this case? And so making the Parent have full ownership of the vec, and the vec of it's children..?
Trying annotate the lifetime like the following...
pub struct Parent1<'a> { // <----- unused parameter
children: Vec<Child>,
idx: usize,
}
...(as in the examples below) doesn't seem to work here as we have no field consuming the 'a
in the struct. I also get the help message consider removing
'a, referring to it in a field, or using a marker such as PhantomData
....
Second try: children as &Vec<Child>
or Vec<&Child>
When using either of &Vec<Child>
or Vec<&Child>
, the lifetime annotation works as expected, giving the expected result:
let vec:&Vec<Child> = &vec![Child {}, Child {}];
for child:&Child in Parent2::new(vec) {
println!("- &child:{:?}", child);
}
Here's the implementation for &Vec<Child>
:
#[derive(Debug)]
pub struct Parent2<'a> {
children: &'a Vec<Child>,
idx: usize,
}
impl<'a> Parent2<'a> {
fn new(children: &'a Vec<Child>) -> Self {
Self { children, idx: 0 }
}
}
impl<'a> Iterator for Parent2<'a> {
type Item = &'a Child;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.children.len() {
let item = &self.children[self.idx];
self.idx += 1;
return Some(&item);
}
None
}
}
(The Vec<&Child>
is identical except for the swapped reference annotations.)
Question 3: As both variants seem to work fine, are there any obvious reasons why to choose one over the other (&Vec<Child>
or Vec<&Child>
)?
Thanks!