【问题标题】:Confusion about Rust HashMap and String borrowing关于 Rust HashMap 和 String 借用的困惑
【发布时间】:2016-10-26 18:53:18
【问题描述】:

这个程序接受一个整数 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]);
    }
}

程序按预期工作:

3
a 1
["a", "1"]
b 2
["b", "2"]
c 3
["c", "3"]

当我尝试将这些已解析的字符串放入 HashMap 并取消注释 map.insert(data[0], data[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() {
...
}
^

我不明白为什么会出现这个错误,因为我认为map.insert() 表达式根本没有借用字符串input

【问题讨论】:

    标签: hashmap rust borrowing


    【解决方案1】:

    split_whitespace() 不会给你两个新的 Strings 包含(副本)输入的非空白部分。相反,您将获得两个对input 管理的内存的引用,类型为&amp;str。因此,当您尝试清除 input 并读取下一行输入时,您会尝试覆盖哈希映射仍在使用的内存。

    为什么split_whitespace(以及许多其他字符串方法,我应该补充)通过返回&amp;str 使事情复杂化?因为它通常就足够了,并且在这些情况下它避免了不必要的副本。然而,在这种特定情况下,最好显式复制字符串的相关部分:

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

    【讨论】:

    • 谢谢@delnan!您的回答确实澄清了我为什么会收到错误。但是map.insert(data[0].clone(), data[1].clone()); 不起作用。我设法通过将let mut map = HashMap::&lt;&amp;str, &amp;str&gt;::new(); 更改为let mut map = HashMap::&lt;String, String&gt;::new(); 并使用map.insert(data[0].to_owned(), data[1].to_owned()); 来解决该错误。有没有更好的解决方案,不涉及分配额外的内存?
    • @B.Wang 哦,对不起,那是我的大脑放屁。不,没有避免分配额外内存的好方法。从根本上说,需要有一个String 来拥有&amp;strs 指向的数据,并且它不能是input,因为它会被反复覆盖。您可以Strings 放入一个单独的向量中(使用mem::replace 和一个空的stirng),但这仍然需要分配向量。请注意,您不会在内存中拥有所有数据的两个副本,因为 input 已被回收。
    猜你喜欢
    • 2020-09-22
    • 2015-04-28
    • 1970-01-01
    • 2014-10-30
    • 2011-12-13
    • 2017-12-04
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多