我正在使用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) => ()
}
}
答案 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; Lexer
和Lexer
- &gt; LexerItems
,然后你真正匹配标准库中的迭代器。
如果你的问题是真的我如何保持对从stdin读取的数据的引用,这是一个不同的问题,并且与你的原始陈述相差甚远。