与(表面上)看起来非常安全的短暂寿命值混淆
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。这是有道理的,因为我们不知道我们正在迭代的项目是否 Copy
able。但是,该参考必须有一个地方可以住。那个住的地方就是 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
,因此值无处可存,因此引用在同一行中消亡声明。
我在用 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。这是有道理的,因为我们不知道我们正在迭代的项目是否 Copy
able。但是,该参考必须有一个地方可以住。那个住的地方就是 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
,因此值无处可存,因此引用在同一行中消亡声明。