rust - 共享生命周期的力场

标签 rust

我使用的是 Rust 0.13,对 Rust 还是个新手。 我有一个想要拥有字符串 input 的结构,但我有想要使用该字符串的切片的代码,work

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

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

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 的 View 无效。 这是一个合理的解释吗?

有没有办法指定这些字段以某种方式相互关联? 我认为如果我可以指定 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) => ()
    }
}

最佳答案

我认为你的问题可以通过增加一层来解决。你可以有一个层来收集你的词法分析器的规则,然后你创建一个新的结构来实际执行词法分析。这与 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 -> LexerLexer -> LexerItems,然后你' d 真正匹配标准库中的迭代器。

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

关于rust - 共享生命周期的力场,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27694413/

相关文章:

rust - 有什么方法可以为受特征限制的任何类型实现 Add 特征吗?

rust - Visitor 特性如何只允许部分实现?

rust - 无法在安全的 Rust 中创建循环链表;不安全版本崩溃

rust - 如何为构建器提供可变引用,但仅提供对构建对象的不可变引用?

rust - [Rust 枚举] : How to get data value from mixed type enum in rust?

parallel-processing - 并行处理 vec : how to do safely, 还是不使用不稳定的功能?

rust - 可以在稳定的编译器上控制 Rust 结构对齐吗?

rust 宏扩展忽略标记 `,` 和任何后续标记

generics - 如何在结构/特征、常规变量声明和函数中最好地实现泛型?

rust - Rust中的“cannot return value referencing temporary value”和内部可变性