问题
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 String
s; 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 String
s instead of &str
s. 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