与(表面上)看起来非常安全的短暂寿命值混淆

Confusion with short lived lifetimed values that (on the surface) seem perfectly safe

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

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

我的词法分析器有一个 next 函数,其目的是提前查看下一个字符并 return 它。

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() 的值寿命不够长,这对我来说很有意义。我只在该行中引用 return 并调用另一个函数,我想它是 return 使用迭代器指向下一个位置的字符的指针。我天真的解决方案是:

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 中借用的,但不确定是什么将它从借用的上下文中移出。

编辑

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

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

如评论中所述,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 returns 一个 reference。这是有道理的,因为我们不知道我们正在迭代的项目是否 Copyable。但是,该参考必须有一个地方可以住。那个住的地方就是 Peekable 迭代器本身! Peekable 分配足够的 space 来存储 "next" 元素。当您调用 peek 时,它会推进底层迭代器,存储值,然后 returns 引用。查看 peek 的函数签名以查看在代码中捕获的内容:

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

您可以重新添加明确的生命周期:

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

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