首页 > 解决方案 > 回归自我以避免搬出借用内容

问题描述

我正在尝试在 Rust 中实现 Monkey 玩具语言。我现在正在尝试生成和 AST,但在此之前,我需要有一个正常运行的解析器。我已经有了我的词法分析器。

所以我的解析器的相关部分如下所示:

struct Parser<'a> {
    lexer: lexer::Lexer<'a>,
    current_token: Token<'a>,
    peek_token: Token<'a>,
}

impl<'a> Parser<'a> {
    // Create a new parser.
    // Depends on a lexer capable of iterating over
    // the tokens.
    pub fn new(mut lexer: lexer::Lexer<'a>) -> Parser {
        // constructor
    }

    // Read the next token.
    //
    // Returns self to avoid weird `move out of
    // borrowed content` issue?
    fn next_token(mut self) -> Self {
        self.current_token = self.peek_token;
        self.peek_token = self.lexer.next_token();
        self
    }
}

问题出在next_token功能上。我真的很希望它可以与借来的 一起使用&self,如下所示:

// Read the next token.
fn next_token(&mut self) {
    self.current_token = self.peek_token;
    self.peek_token = self.lexer.next_token();
}

但是编译器抱怨移出借来的内容。现在,我明白为什么会发生这种情况了:我只是在借self,我不能执行从self.peek_tokento的迁移,self.current_token因为我不拥有它。

不过,我的问题是,回归Self是最好的策略吗?返回的代码Self工作正常,但界面变得非常非常难看。

#[test]
fn test_next_token() {
    let l = lexer::Lexer::new("let answer = 42;");
    let p = Parser::new(l);
    assert_eq!(p.current_token, Token::Let);
    let p = p.next_token();
    assert_eq!(p.current_token, Token::Ident("answer"));
}

有没有我没有看到的替代方案?这是 Rust 中的常见习语吗?

这是游乐场的链接。

标签: rustborrow-checker

解决方案


您可以使用std::mem::replace

use std::mem;

// Read the next token.
fn next_token(&mut self) {
    self.current_token = mem::replace(&mut self.peek_token, self.lexer.next_token());
}

replace将第二个参数存储到第一个参数中,并返回第一个参数的当前值,然后我们将其分配给current_token.


推荐阅读