I'm trying to write a generic function that creates a default value and iterates through its internal "buffer." All this happens within the function with no arguments nor return values. I seem to have the lifetimes declared incorrectly and I am having a hard time setting them correctly for this to work.
Here is an example type that implements the Default
and IntoIterator
traits, as well as a new trait called Foo
that requires one method.
trait Foo<T> {
fn add(&mut self, T);
}
struct FooBar<T> {
buf: Vec<Option<T>>,
len: usize,
}
impl<T> FooBar<T> {
fn new() -> Self {
let buf = Vec::new();
let len = 0;
Self { buf, len }
}
fn iter(&self) -> FooBarIter<T> {
FooBarIter { foo: self, pos: 0 }
}
}
impl<T> Foo<T> for FooBar<T> {
fn add(&mut self, val: T) {
self.buf.push(Some(val));
self.len += 1;
}
}
impl<T> Default for FooBar<T> {
fn default() -> Self {
Self::new()
}
}
impl<'a, T: 'a> IntoIterator for &'a FooBar<T> {
type Item = &'a T;
type IntoIter = FooBarIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
FooBar
just adds values to a vector which it owns. To only allow a non-consuming iteration, I defined an iterator which borrows the underlying Vec
and maintains the "current" index during the iteration, returning a reference to each element which the consumer borrows.
struct FooBarIter<'a, T: 'a> {
foo: &'a FooBar<T>,
pos: usize,
}
impl<'a, T> Iterator for FooBarIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.foo.len <= self.pos {
return None;
}
self.pos += 1;
self.foo.buf[self.pos - 1].as_ref()
}
}
A generic function creates a default value, adds some items (of type &str
), then iterates though them by reference. I seem to have declared the lifetimes incorrectly because Rust complains that the borrowed value of FooBar
doesn't live long enough. However, it says that it lives until the end of the function, so I'm confused as to how long Rust is expecting the borrow to actually live.
fn start<'a, T: 'a>()
where
T: Foo<&'a str> + Default,
&'a T: IntoIterator<Item = &'a &'a str>,
{
let mut f = T::default();
f.add("abcd");
f.add("efgh");
for val in &f {
println!("{}", *val);
}
f.add("ijkl");
for val in &f {
println!("{}", *val);
}
}
fn main() {
start::<FooBar<&str>>();
}
Here is the error which states that that &f
does not live long enough because the "borrowed value only lives until" the end of the function.
error[E0597]: `f` does not live long enough
--> src/main.rs:70:17
|
70 | for val in &f {
| ^ does not live long enough
...
73 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 61:1...
--> src/main.rs:61:1
|
61 | / fn start<'a, T: 'a>()
62 | | where
63 | | T: Foo<&'a str> + Default,
64 | | &'a T: IntoIterator<Item = &'a &'a str>,
... |
72 | | }
73 | | }
| |_^
I've also tried setting a different lifetime parameter for the &'a IntoIterator
trait, but then I end up going around in circles for other errors, not really getting close to setting the correct lifetimes.
To further illustrate what I'm trying to achieve with FooBar
, here is an example of what I'm trying to do if FooBar
was instead a Vec
.
fn start() {
let mut f = Vec::new();
f.push("abcd");
f.push("efgh");
for val in &f {
println!("{}", *val);
}
f.push("ijkl");
for val in &f {
println!("{}", *val);
}
}
Am I even on the right track with trying to figure out the lifetime parameters, or is it something else entirely?