Rust 从循环内部将借用的值存储到外部范围中的容器?

Rust 从循环内部将借用的值存储到外部范围中的容器?,rust,Rust,我给自己布置了一个小任务,学习一些基本的防锈知识。任务是: 从stdin中读取一些键值对,并将它们放入hashmap中 然而,事实证明,这是一个比预期更棘手的挑战。主要是因为对生命的理解。下面的代码是我经过几次实验后得到的,但是编译器一直在对我大喊大叫 use std::io; use std::collections::HashMap; fn main() { let mut input = io::stdin(); let mut lock =

我给自己布置了一个小任务,学习一些基本的防锈知识。任务是:

从stdin中读取一些键值对,并将它们放入hashmap中

然而,事实证明,这是一个比预期更棘手的挑战。主要是因为对生命的理解。下面的代码是我经过几次实验后得到的,但是编译器一直在对我大喊大叫

use std::io;
use std::collections::HashMap;

fn main() {
    let mut input       = io::stdin(); 
    let mut lock        = input.lock(); 
    let mut lines_iter  = lock.lines();

    let mut map         = HashMap::new();

    for line in lines_iter {
        let text                = line.ok().unwrap();
        let kv_pair: Vec<&str>  = text.words().take(2).collect();

        map.insert(kv_pair[0], kv_pair[1]);
    }

    println!("{}", map.len());
}
据我所知,这是因为“文本”的生存期仅限于循环的范围。 因此,我在循环中提取的键值对也绑定到循环边界。因此,将它们插入外部映射将导致指针悬空,因为每次迭代后“文本”将被销毁。(如果我错了,请告诉我)

最大的问题是:如何解决这个问题

我的直觉是:

创建键值对的“自有副本”,并将其生存期“扩展”到外部范围。。。。但我不知道如何做到这一点

“文本”的生存期仅限于循环的范围。因此,我在循环中提取的键值对也绑定到循环边界。因此,将它们插入外部映射将导致指针悬空,因为每次迭代后“文本”将被销毁

听起来不错

制作键值对的“自有副本”

拥有的
&str
字符串

map.insert(kv_pair[0].to_string(), kv_pair[1].to_string());
编辑

下面是原始代码,但我已经更新了上面的答案,使之更加地道

map.insert(String::from_str(kv_pair[0]), String::from_str(kv_pair[1]));

在Rust
1.1
中,函数
单词
被标记为已弃用。现在您应该使用
split_空格

这里有一个替代解决方案,它更具功能性和惯用性(适用于
1.3

使用std::io:{self,BufRead};
使用std::collections::HashMap;
fn main(){
设stdin=io::stdin();
//迭代所有行,“更改”这些行并收集到`HashMap`
let map:HashMap=stdin.lock().lines().filter_map(| line_res |{
//将'Result'转换为'Option',并将'Some'-值映射到一对
//'String's
line|res.ok().map(| line |{
让kv:Vec=line.split_whitespace().take(2.collect();
(千伏[0]。归你所有(),千伏[1]。归你所有()
})
}).收集();
println!(“{}”,map.len());
}

谢谢!这解决了我的问题。我经常读到字符串是&str的“自有版本”。。。。但现在我了解了它的一个“真实”应用程序。我刚刚发现,你也可以在&str上调用x.to_string(),而不是从&str(x)调用string::from_str。@forgemo不仅可以,它被认为更地道。@SteveKlabnik@forgemo我对_string有点了解,所以我一直在避免使用它。对于我的代码,通过切换,我看到性能提高了约13%。@Shepmaster是的,最近几天发生了一些变化,这应该会有所帮助
map.insert(String::from_str(kv_pair[0]), String::from_str(kv_pair[1]));
use std::io::{self, BufRead};
use std::collections::HashMap;

fn main() {
    let stdin = io::stdin();

    // iterate over all lines, "change" the lines and collect into `HashMap`
    let map: HashMap<_, _> = stdin.lock().lines().filter_map(|line_res| {
        // convert `Result` to `Option` and map the `Some`-value to a pair of
        // `String`s
        line_res.ok().map(|line| {
            let kv: Vec<_> = line.split_whitespace().take(2).collect();
            (kv[0].to_owned(), kv[1].to_owned())
        })
    }).collect();

    println!("{}", map.len());
}