重构解析器代码以避免借用检查器问题

Refactor parser code to avoid borrow checker issue

重构此解析器代码以避免借用检查器问题的最佳方法是什么?

pub type Token=u8;
pub trait Stream {
    type Item;
    fn next(&mut self) -> Option<&Self::Item>;
    fn peek(&mut self) -> Option<&Self::Item>;
}

#[derive(Clone)]
pub struct Parser {
    input: Vec<Token>,
    position: usize,
}

pub type ParseError = String;
pub type ParseResult<T> = Result<T, ParseError>;

impl Stream for Parser {
    type Item = Token;

    fn next(&mut self) -> Option<&Token> {
        let token = self.input.get(self.position);
        self.position += 1;
        token
    }

    fn peek(&mut self) -> Option<&Token> {
        self.input.get(self.position + 1)
    }
}

fn parse_expr(stream: &mut Parser) -> ParseResult<()> {
    match stream.peek() { // ~~ borrowed stream here
        None => Err(String::from("No more tokens")),
        Some(t) => match t {
            &0 => parse_number_literal(stream), // ~~ and here
            &1 => panic!("parse string"),
            &2 => panic!("parse character"),
            _ => Err(String::from("Unexpected Token")),
        }
    }
}

fn parse_number_literal(stream: &mut Parser) -> ParseResult<()> {
    let token = stream.next();
    Ok(())
}

fn main(){}

关于 cannot borrow*streamas mutable more than once at a time 的编译器投诉。阅读其他 Whosebug 问题仅回答了为什么会出现此问题,但未回答如何解决问题。

您的 peek 函数不需要 &mut self,仅使用 &self 就可以完全解决您的错误并为您提供 cannot borrow *stream as mutable because it is also borrowed as immutable。无论如何,在不需要的时候避免 mut 更好。

您的问题是您将 Token 引用绑定到 t,因此借用不会结束。你不需要多级 match,并且可以用

做同样的事情
fn parse_expr(stream: &mut Parser) -> ParseResult<()> {
    match stream.peek() {
        None => Err(String::from("No more tokens")),
        Some(&0) => parse_number_literal(stream),
        Some(&1) => panic!("parse string"),
        Some(&2) => panic!("parse character"),
        _ => Err(String::from("Unexpected Token")),
    }
}

或者您可以将 peek 更改为

fn peek(&self) -> Option<Token> {
    self.input.get(self.position + 1).cloned()
}

这不会产生借用问题,但会克隆数据。