关于Rust HashMap和字符串借用的混淆

关于Rust HashMap和字符串借用的混淆,hashmap,rust,borrowing,Hashmap,Rust,Borrowing,此程序接受整数N,后跟N行,其中包含两个由空格分隔的字符串。我想使用第一个字符串作为键,第二个字符串作为值,将这些行放入HashMap: use std::collections::HashMap; use std::io; fn main() { let mut input = String::new(); io::stdin().read_line(&mut input) .expect("unable to read line"); let

此程序接受整数N,后跟N行,其中包含两个由空格分隔的字符串。我想使用第一个字符串作为键,第二个字符串作为值,将这些行放入
HashMap

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

fn main() {
    let mut input = String::new();
    io::stdin().read_line(&mut input)
        .expect("unable to read line");
    let desc_num: u32 = match input.trim().parse() {
        Ok(num) => num,
        Err(_) => panic!("unable to parse")
    };

    let mut map = HashMap::<&str, &str>::new();
    for _ in 0..desc_num {
        input.clear();
        io::stdin().read_line(&mut input)
            .expect("unable to read line");
        let data = input.split_whitespace().collect::<Vec<&str>>();
        println!("{:?}", data);
        // map.insert(data[0], data[1]);
    }
}
当我尝试将那些解析的字符串放入
HashMap
并取消
map.insert(数据[0],数据[1])的注释时,编译失败,出现以下错误:

error: cannot borrow `input` as mutable because it is also borrowed as immutable [E0502]
        input.clear();
        ^~~~~
note: previous borrow of `input` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `input` until the borrow ends
        let data = input.split_whitespace().collect::<Vec<&str>>();
                   ^~~~~
note: previous borrow ends here
fn main() {
...
}
^
错误:无法将'input'作为可变项借用,因为它也是作为不可变项借用的[E0502]
input.clear();
^~~~~
注:“input”之前的借用发生在此处;不可变借用阻止“input”的后续移动或可变借用,直到借用结束
让data=input.split_whitespace().collect::();
^~~~~
注:以前的借阅到此结束
fn main(){
...
}
^
我不明白为什么会出现这个错误,因为我认为
map.insert()
表达式根本没有借用字符串
input

split\u whitespace()
不会给您两个新的
字符串
包含输入的非空白部分(副本)。相反,您会在由
input
管理的内存中获得两个
&str
类型的引用。因此,当您尝试清除
input
并将下一行输入读入时,您将尝试覆盖哈希映射仍在使用的内存

为什么
split_whitespace
(以及我应该补充的许多其他字符串方法)通过返回
&str
,使事情变得复杂?因为这已经足够了,在这种情况下,它可以避免不必要的拷贝。但是,在这种特定情况下,最好显式复制字符串的相关部分:

map.insert(data[0].clone(), data[1].clone());

谢谢你@delnan!你的回答确实澄清了我为什么会出错。但是
map.insert(数据[0].clone(),数据[1].clone())不起作用。通过更改
let mut map=HashMap:::new(),我成功地绕过了错误
to
let mut-map=HashMap:::new()并使用
map.insert(数据[0]。到_-owned(),数据[1]。到_-owned())。有没有更好的解决方案不需要分配额外的内存?@B.Wang哦,对不起,那是我的大脑放屁。不,没有好的方法可以避免分配额外的内存。基本上,需要有一个
字符串
来拥有
&str
点所在的数据,并且它不能是
输入
,因为该字符串会被重复覆盖。您可以将
字符串
s放入一个单独的向量中(使用
mem::replace
和一个空stirng),但这仍然需要分配向量。不过请注意,内存中不会有所有数据的两个副本,因为
input
是循环使用的。
map.insert(data[0].clone(), data[1].clone());