2

我在用 Rust 编写词法分析器时遇到问题,其中某些函数开始抱怨简单的片段,否则这些片段看起来无害。这开始变得令人烦恼,因为错误消息无法帮助我查明问题的原因,所以这是我在同一周内第二次接触同一个程序(上一个问题在这里)。

我读过这本书,我已经明白了我能从中得到的一切。我还观看/阅读了许多其他讨论生命周期(显式和隐式)的文章和视频,并且在大多数情况下,借用和移动背后的概念非常有意义,除了以下情况:

我的词法分析器有一个next功能,其目的是查看下一个字符并返回它。

struct Lexer<'a> {
    src: str::Chars<'a>,
    buf: String,
    // ... not important
}

impl<'a> Lexer<'a> {
    // ... not relevant

    // originally this -> Option<&char> which caused it's own slew of problems
    // that I thought dereferencing the character would solve.
    fn next(&self) -> Option<char> {
        let res = self.src.peekable().peek();
        // convert Option<&char> to Option<char>
        match res {
            Some(ref c) => Some(*c.clone()),
            None => None
        }
    }

    // ... not relevant
}

我这样做时遇到的错误是:

error: borrowed value does not live long enough
       let res = self.src.peekable().peek();
                 ^~~~~~~~~~~~~~~~~~~

我从这个错误中了解到,来自的价值peekable()不够长,这对我来说很有意义。我只是引用该行中的返回并调用另一个函数,我想它是用迭代器返回一个指向下一个位置的字符的指针。我对此的天真解决方案是:

let mut peeker = self.src.peekable();
let res = peeker.peek();

如果我实施此解决方案,我会看到一个不同的错误,这对我来说也没有意义:

error: cannot move out of borrowed content
       let mut peeker = self.src.peekable();
                        ^~~~

我不太确定是什么self从借来的上下文中移出(我知道它是从借来的,&self但不确定是什么将它从借来的上下文中移出。

编辑

我提出了一个细节非常不准确的问题。包含这些详细信息的帖子部分已根据实际情况进行了更新——我混合了两种不同的情况,我遇到了类似的错误(至少与我相似)。

4

1 回答 1

5

让我们从第二个错误开始。

正如评论中提到的,Iterator::peekable是一个迭代器适配器,它使用它将使其可窥视的迭代器一个小复制:

let values = [1,2,3];
let mut iterator = values.iter();
iterator.peekable(); // Consumes `iterator`
iterator.next(); // Not available anymore!

您可以使用Iterator::by_ref来获取可以自己使用的参考。请注意,底层迭代器仍将是高级的!

let values = [1,2,3];
let mut iterator = values.iter();
iterator.by_ref().peekable();
iterator.next();

在您的情况下,您试图从借用的结构(通过&self)中消耗值,该结构具有特定的错误cannot move out of borrowed content


让我们看看你原来的错误:

let values = [1,2,3];
let next = values.iter().peekable().peek();

这里的问题是peek返回一个引用。这是有道理的,因为我们不知道我们正在迭代的项目是否Copy能够。然而,这个参考必须有地方住。住的地方就是Peekable迭代器本身!Peekable分配足够的空间来存储“下一个”元素。当您调用 时peek,它会推进底层迭代器,存储值,然后返回引用。查看函数签名peek以查看在代码中捕获的内容:

fn peek(&mut self) -> Option<&I::Item>

您可以将生命周期重新添加为显式:

fn peek<'a>(&'a mut self) -> Option<&'a I::Item>

在单行版本中,您创建然后销毁Peekable因此值无处可存,因此引用在同一语句中消失。

于 2015-04-22T19:20:33.747 回答