2016-04-29 36 views
0

我想不通为什么我的本地var线does not live long enough。你可以看到我的代码在下面。它在Rust的游乐场上工作。错误:`线`活得不够长,但在操场上没问题

我可能有这个问题的想法:我使用一个结构(加载是这个结构的函数)。由于我想将行的结果存储在结构的成员中,因此可能是问题所在。但我不明白该怎么做才能解决这个问题。

pub struct Config<'a> { 
    file: &'a str, 
    params: HashMap<&'a str, &'a str> 
} 

impl<'a> Config<'a> { 
    pub fn new(file: &str) -> Config { 
     Config { file: file, params: HashMap::new() } 
    } 

    pub fn load(&mut self) ->() { 
     let f = match fs::File::open(self.file) { 
      Ok(e) => e, 
      Err(e) => { 
       println!("Failed to load {}, {}", self.file, e); 
       return; 
      } 
     }; 
     let mut reader = io::BufReader::new(f); 
     let mut buffer = String::new(); 

     loop { 
      let result = reader.read_line(&mut buffer); 

      if result.is_ok() && result.ok().unwrap() > 0 { 
       let line: Vec<String> = buffer.split("=").map(String::from).collect(); 

       let key = line[0].trim(); 
       let value = line[1].trim(); 

       self.params.insert(key, value); 
      } 

      buffer.clear(); 
     } 
    } 
    ... 
} 

而且我得到这个错误:

src/conf.rs:33:27: 33:31 error: `line` does not live long enough 
src/conf.rs:33     let key = line[0].trim(); 
             ^~~~ 
src/conf.rs:16:34: 41:6 note: reference must be valid for the lifetime 'a as defined on the block at 16:33... 
src/conf.rs:16  pub fn load(&mut self) ->() { 
src/conf.rs:17   let f = match fs::File::open(self.file) { 
src/conf.rs:18    Ok(e) => e, 
src/conf.rs:19    Err(e) => { 
src/conf.rs:20     println!("Failed to load {}, {}", self.file, e); 
src/conf.rs:21     return; 
       ... 
src/conf.rs:31:87: 37:14 note: ...but borrowed value is only valid for the block suffix following statement 0 at 31:86 
src/conf.rs:31     let line: Vec<String> = buffer.split("=").map(String::from).collect(); 
src/conf.rs:32 
src/conf.rs:33     let key = line[0].trim(); 
src/conf.rs:34     let value = line[1].trim(); 
src/conf.rs:35 
src/conf.rs:36     self.params.insert(key, value); 
       ... 
+0

添加结构定义,以便我们可以知道'self.params'类型。 – malbarbo

+0

完成了,我加了很多结构 – Kadok

回答

1

使用迭代器返回有在实现为什么这不起作用三个步骤。

let line: Vec<String> = buffer.split("=").map(String::from).collect(); 
let key = line[0].trim(); 
let value = line[1].trim(); 
self.params.insert(key, value); 
  1. lineStringVec,这意味着矢量拥有包含其的字符串。其效果是当矢量从内存中释放时,元素和字符串也被释放。
  2. 如果我们看看string::trimhere,我们看到它需要并返回&str。换句话说,该函数不会分配任何东西或转移所有权 - 它返回的字符串只是原始字符串的一部分。所以如果我们要释放原始字符串,修剪后的字符串将不会有有效的数据。

  3. HashMap::insert的签名是fn insert(&mut self, k: K, v: V) -> Option<V>。该函数同时移动键和值,因为只要它们位于散列映射中,它们就需要有效。我们想给hashmap两个字符串。然而,keyvalue只是引用由矢量所拥有的字符串 - 我们只是借用它们 - 所以我们不能将它们放弃。

解决方法很简单:在拆分字符串后复制字符串。

let line: Vec<String> = buffer.split("=").map(String::from).collect(); 
let key = line[0].trim().to_string(); 
let value = line[1].trim().to_string(); 
self.params.insert(key, value); 

这将分配两个新字符串,并将修剪后的切片复制到新字符串中。


我们可以移动的串出的载体,如果我们没有在修剪之后的字符串(即Vec::remove。);我无法找到一个简单的方法来修剪一个字符串而不用分配一个新的字符串。另外,正如malbarbo提到的,我们可以避免使用map(String::from)完成的额外分配,并且通过简单地省略它们来创建向量,其中collect()

+0

谢谢你的解释! – Kadok

0

在这种情况下,你必须使用String,而不是&str。了解其差异,请参见this

您也可以消除中间载体的创建和split直接

pub struct Config<'a> { 
    file: &'a str, 
    params: HashMap<String, String> 
} 

... 

let mut line = buffer.split("="); 
let key = line.next().unwrap().trim().to_string(); 
let value = line.next().unwrap().trim().to_string(); 
+0

!这简直太简单了! – Kadok

相关问题