创建一个迭代器并将其放入新结构中,而不会打扰借用检查器

时间:2019-05-21 20:23:08

标签: rust iterator lifetime borrow-checker

我正在尝试创建一个词法分析器,该词法分析器使用itertools::PutBackString中的字符进行迭代。我打算将推回迭代器存储在struct中,并为其委派方法,以便我可以按枚举对字符进行分类,然后将其传递给词法分析器核心(尚未编写)的状态机。

借位检查员对我不满意。列表底部附近的方法ParserEventIterator::new导致错误。如何定义生存期或借用期,以便可以对其进行编译?还是我应该使用什么Rustic数据结构设计?

最终,我希望这样做是为了实现适当的特征以使其成为适当的迭代器。 (Rust的新手。在此之前,我已经用28种语言编程,但是这使我很头疼。)

这是一个代码示例:

extern crate itertools;
use itertools::put_back;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

pub enum ParserEvent {
    Letter(char),
    Digit(char),
    Other(char),
}

impl ParserEvent {
    fn new(c: char) -> ParserEvent {
        match c {
            'a'...'z' | 'A'...'Z' => ParserEvent::Letter(c),
            '0'...'9' => ParserEvent::Digit(c),
            _ => ParserEvent::Other(c),
        }
    }
}

impl Display for ParserEvent {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut _ctos = |c: char| write!(f, "{}", c.to_string());
        match self {
            ParserEvent::Letter(letter) => _ctos(*letter),
            ParserEvent::Digit(digit) => _ctos(*digit),
            ParserEvent::Other(o) => _ctos(*o),
        }
    }
}

//  ParserEventIterator
//  Elements ('e) must have lifetime longer than the iterator ('i).
pub struct ParserEventIterator<'i, 'e: 'i> {
    char_iter: &'i mut itertools::PutBack<std::str::Chars<'e>>,
}

impl<'i, 'e: 'i> ParserEventIterator<'i, 'e> {
    fn new(s: &'e std::string::String) -> ParserEventIterator<'i, 'e> {
        // THIS NEXT LINE IS THE LINE WITH THE PROBLEM!!!
        ParserEventIterator {
            char_iter: &mut put_back(s.chars()),
        }
    }

    fn put_back(&mut self, e: ParserEvent) -> () {
        if let Some(c) = e.to_string().chars().next() {
            self.char_iter.put_back(c);
        }
    }
}

impl<'i, 'e: 'i> Iterator for ParserEventIterator<'i, 'e> {
    type Item = ParserEvent;
    fn next(&mut self) -> Option<ParserEvent> {
        match self.char_iter.next() {
            Some(c) => Some(ParserEvent::new(c)),
            None => None,
        }
    }
}

fn main() {
    let mut _i = ParserEventIterator::new(&String::from("Hello World"));
}

On the Rust Playground

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:43:9
   |
43 | /         ParserEventIterator {
44 | |             char_iter: &mut put_back(s.chars()),
   | |                             ------------------- temporary value created here
45 | |         }
   | |_________^ returns a value referencing data owned by the current function

1 个答案:

答案 0 :(得分:1)

好吧,编译器通过反映一个显而易见的问题,几乎可以告诉您解决方案:您不能拥有借用期限不足够长的借用文件,即借用文件指向的堆栈存储器后不存在的位置。功能已被破坏。

之所以会发生这种情况,是因为借用引用了在函数体内新创建的对象(在这种情况下为itertools::struct::PutBack实例)。该实例以及所有对其引用的引用在函数末尾被销毁。因此,编译器阻止您使用所谓的悬挂指针

因此,您应该移动 PutBack实例到您的struct

// ...

pub struct ParserEventIterator<'e> {
    char_iter: itertools::PutBack<std::str::Chars<'e>>
}

impl<'e> ParserEventIterator<'e> {
    fn new(s: &'e std::string::String) -> ParserEventIterator<'e> {
        ParserEventIterator { char_iter: put_back(s.chars()) }
    }

    // ...
}