Gitbook: https://tigercosmos.github.io/lets-build-dbms/

Working on the parser. When I write the following function Parser::new, I encounter lifetime issue. No matter how I add lifetime syntax 'a, ‘b in the function. I cannot pass the compiler.

!FILENAME sql/parser.rs

1
2
3
4
5
6
7
8
9
10
11
12
// The old version
struct Parser<'a> {
tokens: Vec<Symbol<'a>>,
}

impl<'a> Parser<'a> {
fn new(message: &'a str) -> Parser<'a> {
let mut s: Scanner<'a> = Scanner::new(message);
let tokens = s.scan_tokens();
Parser { tokens }
}
}

The error is:

1
2
3
4
5
6
7
8
9
error[E0597]: `s` does not live long enough
--> src/sql/parser.rs:12:39
|
12 | let tokens = s.scan_tokens();
| ^ borrowed value does not live long enough
...
15 | }
| - borrowed value only lives until here
|

That’s very wierd, because I expect the lifetime is correct. Anyway, I give up fighting with lifetime.

Therefore, I change the type of Symbol::name to String rather than &str. Then all errors exist, and I don’t need to add lifetime syntax anymore.

!FILENAME sql/parser.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use sql::lexer::Scanner;
use sql::symbol::Symbol;

struct Parser {
tokens: Vec<Symbol>,
}

impl Parser {
fn new(message: &str) -> Parser {
let mut s: Scanner = Scanner::new(message);
let tokens: Vec<Symbol> = s.scan_tokens();
Parser { tokens }
}
}

It works very well.

This story tells us, when you implement a struct in Rust, it is better to let the type String in the fields. Though it will be stored at heap, but it will be easier with lifetime handling – once using &str as type, you must add 'a lifetime for the struct, and all other fn or struct that use this struct. Also, all objects related to this struct in lifetime 'a, will all live as long as 'a, and it seems not a good idea. So, String next time.