错误:"line"的寿命不足,但在操场上还可以 [英] error: `line` does not live long enough but it's ok in playground

查看:93
本文介绍了错误:"line"的寿命不足,但在操场上还可以的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道为什么我的本地变量行does not live long enough.您可以在下面看到我的代码.它在Rust的操场上工作.

I can't figure it out why my local var line does not live long enough. You can see bellow my code. It work on the Rust's playground.

我可能对这个问题有所了解:我使用一种结构(负载是此结构的函数).因为我想将行的结果存储在我的结构的成员中,所以可能是问题所在.但是我看不出该怎么办才能解决这个问题.

I may have an idea of the issue: I use a structure (load is a function of this structure). As I want to store the result of the line in a member of my struct, it could be the issue. But I don't see what should I do to resolve this problem.

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);
               ...

推荐答案

了解为什么不起作用的过程分为三个步骤.

There are three steps in realizing why this does not work.

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::trim 在这里,我们看到它需要并返回一个&str.换句话说,该函数不会分配任何内容或转移所有权-它返回的字符串只是原始字符串的一部分.因此,如果我们要释放原始字符串,则修剪后的字符串将没有有效的数据.

  1. line is a Vec of Strings, meaning the vector owns the strings its containing. An effect of this is that when the vector is freed from memory, the elements, the strings, are also freed.
  2. If we look at string::trim here, we see that it takes and returns a &str. In other words, the function does not allocate anything, or transfer ownership - the string it returns is simply a slice of the original string. So if we were to free the original string, the trimmed string would not have valid data.

HashMap::insert的签名为fn insert(&mut self, k: K, v: V) -> Option<V>.该函数同时移动键和值,因为只要它们在哈希图中,它们就必须一直有效.我们想给hashmap两个字符串.但是,keyvalue都只是对向量拥有的字符串的引用-我们只是借用它们-因此我们不能放弃它们.

The signature of HashMap::insert is fn insert(&mut self, k: K, v: V) -> Option<V>. The function moves both the key and the value, because these needs to be valid for as long as they may be in the hashmap. We would like to give the hashmap the two strings. However, both key and value are just references to strings which is owned by the vector - we are just borrowing them - so we can't give them away.

解决方案很简单:在分割字符串之后复制它们.

The solution is simple: copy the strings after they have been split.

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

这将分配两个新字符串,并将修整后的片段复制到新字符串中.

This will allocate two new strings, and copy the trimmed slices into the new strings.

如果我们以后不修剪字符串的话,我们可以将字符串从向量中移出(即使用Vec::remove).我无法找到一种在不分配新字符串的情况下修剪字符串的简便方法.

We could have moved the string out of the vector(ie. with Vec::remove), if we didn't trim the strings afterwards; I was unable to find a easy way of trimming a string without allocating a new one.

此外,正如malbarbo所提到的,我们可以通过简单地省略map(String::from)来避免使用map(String::from)进行额外的分配以及使用collect()创建向量的情况.

In addition, as malbarbo mentions, we can avoid the extra allocation that is done with map(String::from), and the creation of the vector with collect(), by simply omitting them.

这篇关于错误:"line"的寿命不足,但在操场上还可以的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆