强制字段共享生命周期

时间:2014-12-29 18:57:24

标签: rust

我正在使用Rust 0.13,而且对Rust很新。 我有一个想要拥有字符串input的结构,但是我有一些代码可以使用该字符串的切片work

pub struct Lexer<'a> {
    input : Option<String>,
    work : &'a str,
    ...
}

我的目标是将一个字符串传递给struct,让它创建自己的副本,然后创建一个指向该字符串的初始切片。理想情况下,我现在可以使用此切片来操作它,因为支持切片的内存不会改变。

pub fn input(&mut self, input : String) {
    self.input = Some(input.clone());
    self.work = self.input.unwrap().as_slice();
}

impl<'lex> Iterator<Token> for Lexer<'lex> {
    fn next(&mut self) -> Option<Token> {
        // ...Do work...
        match regex!("\\S").find(self.work) {
            Some((0, end)) => {
                // Cheap to move the view around
                self.work = self.work.slice_from(end);
            },
            _ => ()
        }
        // ... Do more work ...
    }
}

然而,这不起作用,因为寿命太短:

error: borrowed value does not live long enough
    self.work = self.input.unwrap().as_slice();
                ^~~~~~~~~~~~~~~~~~~

我认为这意味着self.input可能会改变,使self.work的观点无效。 这是一个合理的解释吗?

有没有办法指定这些字段以某种方式相互绑定? 我想如果我可以指定Lexer.input是最终的,那么这可行,但看起来Rust没有办法做到这一点。

编辑:示例呼叫代码

let mut lexer = lex::Lexer::new();

lexer.add("[0-9]+", Token::NUM);
lexer.add("\\+", Token::PLUS);

for line in io::stdin().lock().lines() {
    match line {
        Ok(input) => {
            lexer.input(input.as_slice());
            lexer.lex();
        },
        Err(e) => ()
    }
}

1 个答案:

答案 0 :(得分:2)

我认为您的问题可以通过添加一个图层来解决。您可以拥有一个收集词法分析器规则的图层,然后创建一个实际执行lexing的新结构。这与Rust中迭代器的实现方式相同!

struct MetaLexer<'a> {
    rules: Vec<(&'a str, u32)>,
}

impl<'a> MetaLexer<'a> {
    fn new() -> MetaLexer<'a> { MetaLexer { rules: Vec::new() } }

    fn add_rule(&mut self, name: &'a str, val: u32) {
        self.rules.push((name, val));
    }

    fn lex<'r, 's>(&'r self, s: &'s str) -> Lexer<'a, 's, 'r> {
        Lexer {
            rules: &self.rules,
            work: s,
        }
    }
}

struct Lexer<'a : 'r, 's, 'r> {
    rules: &'r [(&'a str, u32)],
    work: &'s str,
}

impl<'a, 's, 'r> Iterator for Lexer<'a, 's, 'r> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        for &(name, val) in self.rules.iter() {
            if self.work.starts_with(name) {
                self.work = &self.work[name.len()..];
                return Some(val);
            }
        }

        None
    }
}

fn main() {
    let mut ml = MetaLexer::new();
    ml.add_rule("hello", 10);
    ml.add_rule("world", 3);

    for input in ["hello", "world", "helloworld"].iter() {
        // So that we have an allocated string,
        // like io::stdin().lock().lines() might give us
        let input = input.to_string(); 

        println!("Input: '{}'", input);
        for token in ml.lex(&input) {
            println!("Token was: {}", token);
        }
    }
}

真的,您可以重命名MetaLexer - &gt; LexerLexer - &gt; LexerItems,然后你真正匹配标准库中的迭代器。

如果你的问题是真的我如何保持对从stdin读取的数据的引用,这是一个不同的问题,并且与你的原始陈述相差甚远。