Rust中解析器结构的生命周期

时间:2016-12-27 19:08:08

标签: struct rust lifetime

我正在尝试重写我的解析器以允许将字符串传递给parse方法,而不是绑定到struct。

以前,我的代码看起来像这样:

use std::collections::HashMap;
use std::str;

#[derive(Debug)]
pub enum ParserError {
    Generic
}

pub struct Resource(
    pub HashMap<String, String>
);

pub struct Parser<'a> {
    source: str::Chars<'a>
}

impl<'a> Parser<'a> {
    pub fn new(source: &str) -> Parser {
        Parser { source: source.chars() }
    }
    pub fn parse(&mut self) -> Result<Resource, ParserError> {
        let entries = HashMap::new();
        Ok(Resource(entries))
    }
}

fn main() {
    let parser = Parser::new("key1 = Value 1");
    let res = parser.parse();
}

在我的新代码中,我正在尝试这样的事情:

use std::collections::HashMap;
use std::str;

#[derive(Debug)]
pub enum ParserError {
    Generic
}

pub struct Resource(
    pub HashMap<String, String>
);

pub struct Parser<'a> {
    source: Option<str::Chars<'a>>
}

impl<'a> Parser<'a> {
    pub fn new() -> Parser<'a> {
        Parser { source: None }
    }
    pub fn parse(&mut self, source: &str) -> Result<Resource, ParserError> {
        self.source = Some(source.chars());

        let entries = HashMap::new();
        Ok(Resource(entries))
    }
}

fn main() {
    let parser = Parser::new();
    parser.parse("key1 = Value 1");
    parser.parse("key2 = Value 2");
}

但似乎我以一种我不太满意的方式搞乱了生命。我得到的错误是:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> test.rs:22:35
   |
22 |         self.source = Some(source.chars());
   |    

处理此问题的规范方法是什么?如何获取String并将其克隆到Parser结构的生命周期中?

1 个答案:

答案 0 :(得分:1)

完整的错误消息是:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:22:35
   |
22 |         self.source = Some(source.chars());
   |                                   ^^^^^
   |
help: consider using an explicit lifetime parameter as shown: fn parse(&mut self, source: &'a str) -> Result<Resource, ParserError>
  --> src/main.rs:21:5
   |
21 |     pub fn parse(&mut self, source: &str) -> Result<Resource, ParserError> {
   |     ^

按照建议行事:

pub fn parse(&mut self, source: &'a str) -> Result<Resource, ParserError>

允许代码编译和运行(在main中修复无关的不匹配可变性之后)。

要了解差异,您必须先了解lifetime elision

您的原始代码是:

fn new(source: &str) -> Parser // with elision
fn new<'b>(source: &'b str) -> Parser<'b> // without elision

简而言之,结构的通用生命周期参数'a与传入字符串的生命周期相关联。

您的新代码更复杂:

fn new() -> Parser<'b>

// with elision
fn parse(&mut self, source: &str) -> Result<Resource, ParserError>
// without elision
fn parse<'c, 'd>(&'c mut self, source: &'d str) -> Result<Resource, ParserError>

用语言来说,结构的通用生命周期参数'a仍由new的调用者定义,但现在它与构造函数中的任何内容都没有关联。在调用parse时,您试图传入一个不相关生命周期的字符串并存储对它的引用(通过Chars迭代器)。由于两个生命周期无关,你不能确定它会持续足够长的时间。