Textfile-parsing function fails to compile owing to lifetime/borrow error

安稳与你 提交于 2020-01-05 02:54:07

问题


NB. This post was originally part of a larger post that contained two questions (that I'd believed were one error manifesting itself differently), but to comply with site guidelines I've split it into two separate posts, of which this is the second. The first post is here.

I'm trying to parse a simple config text file, which contains one three-word entry per line, laid out as follows:

ITEM name value
ITEM name value
//etc.

I've reproduced the function which does the parsing (and the subsequent compilation error) here (and on the Rust playground):

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;
use std::collections::HashMap;

fn main() { }

pub fn parse(path: &Path) -> config_struct {

    let file = File::open(&path).unwrap();
    let reader = BufReader::new(&file);
    let line_iterator = reader.lines();
    let mut connection_map = HashMap::new();
    let mut target_map = HashMap::new();

    for line in line_iterator {

        let line_slice = line.unwrap();
        let word_vector: Vec<&str> = line_slice.split_whitespace().collect();

        if word_vector.len() != 3 { continue; }

        // no match statement   
        connection_map.insert(word_vector[1], word_vector[2]);
    }

    config_struct { connections: connection_map, targets: target_map }
}

pub struct config_struct<'a>  {
    // <name, value>
    connections: HashMap<&'a str, &'a str>,
    // <name, value>
    targets: HashMap<&'a str, &'a str>,
}
<anon>:20:38: 20:48 error: `line_slice` does not live long enough
<anon>:20         let word_vector: Vec<&str> = line_slice.split_whitespace().collect();
                                               ^~~~~~~~~~
note: in expansion of for loop expansion
<anon>:17:5: 26:6 note: expansion site
<anon>:9:44: 29:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 9:43...
<anon>:9 pub fn parse(path: &Path) -> config_struct {
<anon>:10 
<anon>:11     let file = File::open(&path).unwrap();
<anon>:12     let reader = BufReader::new(&file);
<anon>:13     let line_iterator = reader.lines();
<anon>:14     let mut connection_map = HashMap::new();
          ...
<anon>:19:40: 26:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 19:39
<anon>:19         let line_slice = line.unwrap();
<anon>:20         let word_vector: Vec<&str> = line_slice.split_whitespace().collect();
<anon>:21 
<anon>:22         if word_vector.len() != 3 { continue; }
<anon>:23 
<anon>:24         // no match statement   
          ...
error: aborting due to previous error

In essence, I am having trouble with the borrow-checker; in my code, isn't word_vector populated with owned objects that don't point to line_slice? I figured that perhaps unwrap() or collect() returned a reference and that it was the reference that was going out of scope, but the Rust Docs for unwrap and collect suggest otherwise.


回答1:


A &str cannot exist without something storing the value it contains—it is purely a reference (hence the &).

Reading from the file you get Strings; these provide the storage. But you are dropping them, trying to only return the strings.

Think also of it this way:

pub fn parse(path: &Path) -> config_struct<'???>;

What lifetime should you have for the return value?

The only reason it didn’t complain of that part is that it inferred that the Path reference lifetime and the return value lifetime were the same, which would imply that you are returning a reference to something inside the Path, which you are not.

In such a situation as this, you typically need to store Strings instead of &strs. Convert each &str to a String with .to_owned().



来源:https://stackoverflow.com/questions/31621567/textfile-parsing-function-fails-to-compile-owing-to-lifetime-borrow-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!