简体   繁体   English

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

[英]Lifetime of a parser struct in Rust

I'm trying to rewrite my parser to allow for strings to be passed into the parse method, instead of being bound to the struct. 我正在尝试重写解析器,以允许将字符串传递到parse方法中,而不是绑定到该结构。

Previously, my code looked like this: 以前,我的代码如下所示:

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();
}

and in my new code I'm trying something like this: 在我的新代码中,我正在尝试如下操作:

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");
}

but it seems like I'm messing with lifetimes in a way that I'm not fully comfortable with. 但似乎我以一种我不完全满意的方式弄乱了自己的一生。 The error I get is: 我得到的错误是:

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

What's the canonical way of handling this? 规范的处理方式是什么? How can I take a String and clone it into the lifetime of the Parser struct? 如何获取String并将其克隆到Parser结构的生存期中?

The full error message is: 完整的错误消息是:

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> {
   |     ^

Doing as it suggests: 按照建议进行:

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

Allows the code to compile and run (after fixing the unrelated mismatched mutability in main ). 允许代码编译和运行(在main修复了不相关的不匹配可变性之后)。


To understand the difference, you must first understand lifetime elision . 要了解差异,您必须首先了解生命周期淘汰

Your original code was: 您的原始代码为:

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

In words, the generic lifetime parameter 'a of the struct was tied to the lifetime of the incoming string. 换句话说,该结构的通用生存期参数'a与传入字符串的生存期相关。

Your new code was more complicated: 您的新代码更加复杂:

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>

In words, the generic lifetime parameter 'a of the struct is still defined by the caller of new , but now it's not tied to anything from the constructor. 换句话说,该结构的通用生命周期参数'a仍由new的调用者定义,但现在它不再与构造函数中的任何内容绑定。 When calling parse , you were attempting to pass in a string of an unrelated lifetime and store a reference to it (through the Chars iterator). 调用parse ,您试图传入不存在生命周期的字符串并存储对它的引用(通过Chars迭代器)。 Since the two lifetimes were unrelated, you cannot be sure it will last long enough. 由于这两个生命周期是无关的,因此您无法确定其寿命是否足够长。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM