尝试使用存储闭包实现迭代器时,令人困惑的 Rust 生命周期问题

问题描述 投票:0回答:1

我正在尝试编写一个在

&str
上运行的简单文本解析实用程序。我想实现一个接受闭包对象和分隔符字符串的函数,该函数返回一个实现
Iterator
的类型,该类型连续调用闭包对象并在每次调用
next()

时吃掉分隔符

由于我不知道迭代项是什么类型(取决于闭包),所以我想概括这一点,所以它的签名将是

FnMut(&mut Parser) -> Option<T>
。由于它可以选择从解析器存储的字符串中借用,因此我需要插入适当的生命周期。

这是我到目前为止所拥有的:

链接到 Rust Playground

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
特征并未指定它。

如何让我的代码编译?

我想还有一个第二个问题,我一直在代码中添加明确的引用来尝试解决问题。我可以逃脱的最少明确引用数量是多少?

rust borrow-checker
1个回答
0
投票

问题源于

&'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!
    }
}

(游乐场))

© www.soinside.com 2019 - 2024. All rights reserved.