我对 Rust 相当陌生。因此我对借用检查器等没有这么深入的理解。我已经用 C++ 做了一个编译器,所以我尝试在 Rust 中做同样的事情,因为这似乎是一个学习它的好机会。
我已经完成了我的词法分析器,它工作得非常好,而且我对 Rust 总体上也很满意。但借用检查器和生命周期有时会让我失望。当我想创建我的解析器时,我遇到了一个让我相当沮丧的问题。为了给出我的实现的简化结构,我有以下代码:
#[derive(PartialEq)]
enum TokenKind {
Test,
}
struct Token<'a> {
source: &'a str,
kind: TokenKind,
}
struct Parser<'a> {
tokens: &'a [Token<'a>],
position: usize,
}
impl<'a> Parser<'a> {
fn matches(&mut self, kinds: &[TokenKind]) -> Option<&Token> { // rustc: let's call the lifetime of this reference `'1`
let current = match self.current() { // rustc: `self.position` is borrowed here
Some(current) if kinds.contains(¤t.kind) => current,
_ => return None,
};
self.position += 1; // rustc: cannot assign to `self.position` because it is borrowed `self.position` is assigned to here but it was already borrowed
Some(current) // rustc: returning this value requires that `*self` is borrowed for `'1`
}
fn current(&self) -> Option<&Token> {
self.tokens.get(self.position)
}
}
现在我的问题是如何修复此代码?为什么“self.position”已经被“self.current”方法借用了?也许这是一个我不确定的根本问题。
尽管我阅读了借用检查和生命周期的文档,但我不太确定如何解决这个问题。因此,我会很高兴获得一些帮助,即使它只是解决这个确切问题的资源。
现在我的问题是如何修复此代码?为什么“self.position”已经被“self.current”方法借用了?也许这是一个我不确定的根本问题。
虽然 rust 可以在程序上内部分割借用,但它不能在程序上间这样做。
current
是一个 &Token
,但因为它是调用 Parser::current
的结果,所以它与借用 整个 self 相关联。因此,只要该问题尚未解决,您就无法更新 self
的任何成员。
解决方案是仅内联
current
,这样拆分借用是过程内的,并且编译器可以理解发生了什么。
另一种方法是删除
position
并使 tokens
成为(可查看的)迭代器。或者使其成为不可查看的迭代器,但让match
处理“当前令牌”,这是从迭代器获得的最后一个令牌(基本上是相同的结果)。