Rust 返回Self以避免移出借用内容

Rust 返回Self以避免移出借用内容,rust,borrow-checker,Rust,Borrow Checker,我正在尝试在Rust中实现猴子玩具语言。我现在尝试生成和AST,但在此之前,我需要一个功能强大的解析器。我已经有我的lexer了 因此,我的解析器的相关部分如下所示: struct Parser<'a> { lexer: lexer::Lexer<'a>, current_token: Token<'a>, peek_token: Token<'a>, } impl<'a> Parser<'a> {

我正在尝试在Rust中实现猴子玩具语言。我现在尝试生成和AST,但在此之前,我需要一个功能强大的解析器。我已经有我的lexer了

因此,我的解析器的相关部分如下所示:

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
    }
}
// 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\u token
self.current\u 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"));
}
有没有我没有看到的替代方案?这是《铁锈》中常见的成语吗

以下是指向的链接。

您可以使用:


replace
将第二个参数存储到第一个参数中,并返回第一个参数的当前值,然后将其分配给
current\u token

Nice!成功了。看到你的答案,虽然我不认为我理解得很清楚,为什么我以前不能离开变量?我重新检查了借阅规则,没有任何迹象表明你不能移出借阅的内容?很明显,在我最初的代码中,锈蚀会使self.peek_token在移动后失效,因为它可能导致用户在免费后失效,对吗?但是为什么它不这么做而不是说我做不到呢?我想到的唯一原因是可能有另一个线程希望
self.peek_token
有效?简单地说,因为
panic。您将移出
peek\u令牌
,使其无效,并期望通过
next\u令牌()
的结果使其再次有效。但是如果
next\u token()
出现恐慌,并且一些外部代码捕捉到了恐慌,那么您就可以看到结构的视图,其中包含一个无效字段。(顺便说一句,线程不是一个问题,因为
&mut
是独占的,并保证当前没有其他线程正在访问该结构。)通过使用
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());
}