2016-12-27 2 views
0

Я пытаюсь переписать мой синтаксический анализатор, чтобы позволить переносить строки в метод разбора вместо привязки к структуре.Время жизни структуры анализатора в Rust

Раньше мой код выглядит следующим образом:

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

Сообщения полной ошибки:

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). Поскольку две жизни не были связаны друг с другом, вы не можете быть уверены, что это будет длиться достаточно долго.

Смежные вопросы