I'm writing an on demand parser for a learning project and have boiled down the problem to the following short snippet.
struct Token<'a> {
original: &'a str,
}
struct Parser {
source: String,
}
impl Parser {
pub fn parse_token(&mut self) -> Token {
return Token {
original: &self.source[0..3],
};
}
}
fn main() {
let mut parser = Parser {
source: String::from("var x = 5;"),
};
let mut tokens = Vec::new();
let t1 = parser.parse_token();
tokens.push(t1);
let t2 = parser.parse_token();
tokens.push(t2);
}
I can't quite reason about the lifetimes here. I know that all the lifetimes of Token
have to meet or exceed that of parser
, since it owns the data that each Token
references. The problem, I think, is that I'm over-constraining the lifetime somewhere, because the compiler emits this warning:
error[E0499]: cannot borrow `parser` as mutable more than once at a time
--> src\main.rs:27:14
|
24 | let t1 = parser.parse_token();
| -------------------- first mutable borrow occurs here
...
27 | let t2 = parser.parse_token();
| ^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
28 | tokens.push(t2);
| --------------- first borrow later used here
Which makes sense, the real signature of parse_token
is:
pub fn parse_token<'a>(&'a mut self) -> Token<'a>
Which (I think) is saying that the lifetime of the reference to self (parser
) must be the same as the lifetime of the returned Token
. Well, that creates the exact problem the compiler complains about, as it is extending the lifetime of the mutable borrow to that of the Token
, making it impossible to call the function twice essentially. It is a little confusing that the push of t2
is counting as a borrow of parser, though I guess that is just the lifetime of the vec being extended, therefore t1's lifetime being extended
Those are my thoughts. Some help with how to correctly annotate the lifetimes would be appreciated. Also, I know I could not have Token
actually maintain the original text and do something cleverer, but I feel like this should be possible, I just don't know how to "spell" it per se.