I have a calculator parser code set up like so:
struct Parser {
current_index: usize,
tokens: Vec<Token>,
}
impl Parser {
fn new(tokens: Vec<Token>) -> Self {
Parser {
current_index: 0,
tokens: tokens,
}
}
fn consume_token(&mut self) {
self.current_index += 1;
}
fn current_token(&self) -> Result<Token, &str> {
if self.current_index >= self.tokens.len() {
return Err("Current index out of range");
}
Ok(self.tokens[self.current_index])
}
fn primary(&mut self) -> Result<Expression, &str> {
let token = self.current_token().unwrap();
self.consume_token();
match token {
Token::Integer(n) => Ok(Expression::Integer(n)),
Token::OpenParent => {
let expr = self.expression().unwrap();
match self.current_token().unwrap() {
Token::CloseParent => Ok(expr),
_ => Err("syntaxerr"),
}
}
Token::Minus => {
let expr = self.factor().unwrap();
Ok(Expression::Unary(
Operator::Neg,
Box::new(expr),
))
}
_ => {
Err("syntaxerr")
}
}
}
fn factor(&mut self) -> Result<Expression, &str> {
let expr = self.primary().unwrap();
let token = self.current_token().unwrap();
match token {
Token::Power => {
self.consume_token();
let rhs = self.factor().unwrap();
Ok(Expression::Binary(
Operator::Pow,
Box::new(expr),
Box::new(rhs),
))
}
_ => {
Ok(expr)
}
}
}
...
}
I want to change the error handling by using the ? operator. I thought i can just replace the .unwrap with ?, but that causes a borrow checker error.
I tried to change the code like so:
fn primary(&mut self) -> Result<Expression, &str> {
let token = self.current_token()?;
self.consume_token();
match token {
Token::Integer(n) => Ok(Expression::Integer(n)),
Token::OpenParent => {
let expr = self.expression()?;
match self.current_token().unwrap() {
Token::CloseParent => Ok(expr),
_ => Err("syntaxerr"),
}
}
...
}
}
That however causes a compiler error: cannot borrow *self
as immutable because it is also borrowed as mutable
I have read the documentation about ? operator and i don't understand why things change for the borrow checker when using ? instead of unwrap(). Any help would be appreciated.
Someone on reddit answered my question perfectly:
When you result
Result<T, &str>
, it infers that the str borrows from &self. Instead, returnResult<T, &’static str>
so it knows that the str doesn’t borrow from self (or better yet, an enum that can be displayed).