我正在尝试编写一个在
&str
上运行的简单文本解析实用程序。我想实现一个接受闭包对象和分隔符字符串的函数,该函数返回一个实现 Iterator
的类型,该类型连续调用闭包对象并在每次调用 next()
时吃掉分隔符
由于我不知道迭代项是什么类型(取决于闭包),所以我想概括这一点,所以它的签名将是
FnMut(&mut Parser) -> Option<T>
。由于它可以选择从解析器存储的字符串中借用,因此我需要插入适当的生命周期。
这是我到目前为止所拥有的:
struct Parser<'a> {
string: &'a str,
}
impl<'a> Parser<'a> {
// ...
fn at_end(&self) -> bool {
// returns whether we're at the end of the string
false
}
fn expect(&mut self, _s: &str) -> &mut Self {
// expects the next part to be `s` and advances the string
// ...
self
}
fn parse_iter<'b, T: 'a, F: FnMut(&'a mut Self) -> Option<T>>(
&'a mut self,
separator: &'b str,
f: F,
) -> ParseIter<'a, 'b, T, F> {
ParseIter {
parser: self,
func: f,
sep: separator,
skip: false,
}
}
}
struct ParseIter<'a, 'b, T, F>
where
T: 'a,
F: FnMut(&'a mut Parser<'a>) -> Option<T>
{
parser: &'a mut Parser<'a>,
func: F,
sep: &'b str,
skip: bool,
}
impl<'a, 'b, T, F> Iterator for ParseIter<'a, 'b, T, F>
where
T: 'a,
F: FnMut(&'a mut Parser<'a>) -> Option<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.at_end() {
return None;
}
if std::mem::replace(&mut self.skip, true) {
self.parser.expect(self.sep);
}
(self.func)(self.parser) // error here!
}
}
调用闭包的最后一行代码会产生错误:
error: lifetime may not live long enough
--> util\src\parser.rs:156:9
|
140 | impl<'a, 'b, T, F> Iterator for ParseIter<'a, 'b, T, F>
| -- lifetime `'a` defined here
...
147 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
...
156 | (self.func)(self.parser)
| ^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
我的意思是,我认为我什至不理解错误的本质。显然,
&mut self
不能比'a
更长寿,因为它本身就是一个包含生命周期为'a
的引用的对象,那么&mut self
怎么可能比'a
更长寿呢?
但是好吧,从表面上看错误,我想我需要确保
&mut self
也是'a
。但我无法明确命名它,因为 Iterator
特征并未指定它。
如何让我的代码编译?
我想还有一个第二个问题,我一直在代码中添加明确的引用来尝试解决问题。我可以逃脱的最少明确引用数量是多少?
问题源于
&'a mut Parser<'a>
。这种模式是总是错误。 这可以与共享引用一起使用(&'a Parser<'a>
),因为共享引用的生命周期是不同的;独占参考生命周期不是。
尽可能从
&mut Parser
变量中删除生命周期;在需要的地方引入一个新的生命周期参数。
struct Parser<'a> {
string: &'a str,
}
impl<'a> Parser<'a> {
// ...
fn at_end(&self) -> bool {
// returns whether we're at the end of the string
false
}
fn expect(&mut self, _s: &str) -> &mut Self {
// expects the next part to be `s` and advances the string
// ...
self
}
fn parse_iter<'b, 'c, T: 'a, F: FnMut(&mut Self) -> Option<T>>(
&'c mut self,
separator: &'b str,
f: F,
) -> ParseIter<'a, 'b, 'c, T, F> {
ParseIter {
parser: self,
func: f,
sep: separator,
skip: false,
}
}
}
struct ParseIter<'a, 'b, 'c, T, F>
where
T: 'a,
F: FnMut(&mut Parser<'a>) -> Option<T>
{
parser: &'c mut Parser<'a>,
func: F,
sep: &'b str,
skip: bool,
}
impl<'a, 'b, 'c, T, F> Iterator for ParseIter<'a, 'b, 'c, T, F>
where
T: 'a,
F: FnMut(&mut Parser<'a>) -> Option<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.at_end() {
return None;
}
if std::mem::replace(&mut self.skip, true) {
self.parser.expect(self.sep);
}
(self.func)(self.parser) // error here!
}
}
(游乐场))