作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用的是 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
-> Lexer
和 Lexer
-> LexerItems
,然后你' d 真正匹配标准库中的迭代器。
如果您的问题是真的我如何保留对从 stdin 读取的数据的引用,那是一个不同的问题,并且与您的原始陈述相去甚远。
关于rust - 共享生命周期的力场,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27694413/
我是一名优秀的程序员,十分优秀!