Rust 强制字段共享生存期
我用的是Rust 0.13,我对Rust还比较陌生。 我有一个结构想要拥有一个字符串Rust 强制字段共享生存期,rust,Rust,我用的是Rust 0.13,我对Rust还比较陌生。 我有一个结构想要拥有一个字符串输入,但我有一个代码想要处理该字符串的片段,工作 pub struct Lexer<'a> { input : Option<String>, work : &'a str, ... } 我将其解释为,self.input可能会更改,从而使self.work的视图无效。 这是合理的解释吗 有没有办法指定这些字段以某种方式相互关联? 我想,如果我能指定Lex
输入
,但我有一个代码想要处理该字符串的片段,工作
pub struct Lexer<'a> {
input : Option<String>,
work : &'a str,
...
}
我将其解释为,self.input
可能会更改,从而使self.work
的视图无效。
这是合理的解释吗
有没有办法指定这些字段以某种方式相互关联?
我想,如果我能指定Lexer.input
为final,这将起作用,但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) => ()
}
}
我认为你的问题可以通过增加一层来解决。您可以有一个层来收集lexer的规则,然后创建一个新的结构来实际执行lexer。这与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);
}
}
}
struct MetaLexer,
}
恳求{
fn new()->MetaLexer Lexer{
项目类型=u32;
fn下一步(&mut self)->选项{
对于self.rules.iter()中的&(name,val){
如果self.work.以(名称)开头{
self.work=&self.work[name.len()…];
返回一些(val);
}
}
没有一个
}
}
fn main(){
让mut ml=MetaLexer::new();
ml.add_规则(“hello”,10);
ml.add_规则(“世界”,3);
用于输入[“hello”、“world”、“helloworld”].iter(){
//这样我们就有了一个分配的字符串,
//比如io::stdin().lock().lines()可能会给我们
让input=input.to_string();
println!(“输入:'{}',输入);
对于ml.lex中的令牌(&input){
println!(“令牌是:{}”,令牌);
}
}
}
实际上,您可以重命名MetaLexer
->Lexer
和Lexer
->LexerItems
,然后您将真正匹配标准库中的迭代器
如果您的问题是我如何保留从stdin读取的数据的引用,这是一个不同的问题,与您的原始陈述相去甚远。可能重复“如果我可以指定Lexer.input为final”-如果你想要一个永远不会改变的字符串,那听起来像是一个
&str
^^。我同意这一点,但我真的不知道如何处理字符串备份输入:&str
。我发现这样做会把我的Lexer
与它的输入绑定在同一个生命周期,所以我想我不知道我是怎么用C语言写的,然后改用这种方式,“这种方式最终把我的Lexer和我的生活绑在了一起”-是的,你想让你的Lexer与&str
绑定到同一个生命周期-这是Rust唯一能确保你不会对不再存在的字符串进行Lexer,并且它不会在你下面发生变化的方法。这就是为什么我试图将输入移动到Lexer
,让我使用Rust试图提供的不变量。用于考试例如,我可能想调用Lexer.input()
在来自stdin
的多个不同输入上,但如果我使用&str
这样做,我不知何故需要stdin
中的字符串与lexer结构具有相同的作用域,这似乎不可行,或者在内存使用方面根本不符合我的要求。因此,我基本上是使用工厂来计算生命周期正确地说。我喜欢。你知道有一个引用谈到“如何保存从stdin读取的数据的引用”吗?我没有注意到任何类似的引用不是指过时的版本,尽管我可能没有应用.clone()
创意十足。@mattbreant我没有任何直接的参考资料,但我有一些想法可以用来回答一个新问题。然后你也会得到其他人的想法。
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) => ()
}
}
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);
}
}
}