Hello, I'm trying to make a program where i have an iterator that borrows some value from their caller. The iterator life is shorter than its caller so i would expect to be able to do this but I have been trying to get the lifetimes correct for a few days and fail to make the borrow checker happy.
I have made a short example to show what I'm trying to do:
struct Project<'a> {
worker: Worker,
iterator: Option<Box<dyn std::iter::Iterator<Item = String> +'a>>
}
impl <'a> Project<'a> {
fn new(text: String) -> Project<'a> {
Project {
worker: Worker{text: text},
iterator: None,
}
}
fn next<'b>(&'a mut self) -> Option<String> {
if self.iterator.is_none() {
self.iterator = Some(self.worker.fetch());
}
self.iterator.as_mut().unwrap().next()
}
}
struct Worker {
text: String
}
impl Worker {
fn fetch<'a>(&'a self) -> Box<dyn std::iter::Iterator<Item = String> + 'a> {
Box::new(Iterator{ count: 3, text: &self.text })
}
}
struct Iterator<'a> {
count: u8,
text: &'a String
}
impl std::iter::Iterator for Iterator<'_> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match self.count {
0 => None,
_ => {
self.count -= 1;
Some(self.text.clone())
}
}
}
}
fn main() {
let mut project = Project::new(String::from("Hello world"));
println!("{:#?}", project.next());
println!("{:#?}", project.next());
println!("{:#?}", project.next());
println!("{:#?}", project.next());
}
I get the following error when compiling:
error[E0597]: `project` does not live long enough
--> src/main.rs:54:23
|
53 | let mut project = Project::new(String::from("Hello world"));
| ----------- binding `project` declared here
54 | println!("{:#?}", project.next());
| ^^^^^^^ borrowed value does not live long enough
...
58 | }
| -
| |
| `project` dropped here while still borrowed
| borrow might be used here, when `project` is dropped and runs the destructor for type `Project<'_>`
error[E0499]: cannot borrow `project` as mutable more than once at a time
--> src/main.rs:55:23
|
54 | println!("{:#?}", project.next());
| ------- first mutable borrow occurs here
55 | println!("{:#?}", project.next());
| ^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
but I don't understand why this is wrong:
- The iterator is only accessed from
Project.next()
so it should always be valid self
is borrowed inProject.next()
but only for the duration of the call so it seems to me like this should also be valid.
Perhaps there is some annotation missing to explain to Project.worker
will not be dropped before the worker itself?