【问题标题】:Insert into hashmap in a loop循环插入hashmap
【发布时间】:2020-07-10 16:30:31
【问题描述】:

我正在打开一个 CSV 文件并使用 BufReader 读取它并将每一行拆分为一个向量。然后我尝试使用特定列作为键在HashMap 中插入或更新计数。

let mut map: HashMap<&str, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens: Vec<&str> = s.split(&d).collect(); // <-- `s` does not live long enough
    if tokens.len() > c {
        println!("{}", tokens[c]);
        let count = map.entry(tokens[c].to_string()).or_insert(0);
        *count += 1;
    }
}

编译器好心地告诉我s 是短暂的。 Storing from inside a loop a borrowed value to container in outer scope? 建议“拥有”字符串,所以我尝试更改

let count = map.entry(tokens[c]).or_insert(0);

let count = map.entry(tokens[c].to_string()).or_insert(0);

但我得到了错误

expected `&str`, found struct `std::string::String`
help: consider borrowing here: `&tokens[c].to_string()`

当我在 & 前面加上 (&amp;) 时,错误是

creates a temporary which is freed while still in use
note: consider using a `let` binding to create a longer lived

我对借用的 Rust 知识有一些不足。如何让 hashmap 拥有作为键传递的字符串?

【问题讨论】:

  • 你是如何声明map的?
  • 谢谢,添加了地图声明。你解决了我的问题。我将声明更改为 HashMap。我在 rust-lang.org 上使用了一个 hashmap-example,它使用了 &str.
  • 谢谢,我在我们说话的时候就这么做了。您可以将其添加为答案吗?
  • 很难回答您的问题,因为它不包含minimal reproducible example。我们无法分辨代码中存在哪些 crate(及其版本)、类型、特征、字段等。如果您尝试在Rust Playground 上重现您的错误,如果可能的话,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后在edit 您的问题中包含附加信息。您可以使用Rust-specific MRE tips 来减少您在此处发布的原始代码。谢谢!
  • edit 您的问题并粘贴您所遇到的确切和全部错误——这将有助于我们了解问题所在,以便我们提供最佳帮助。有时试图解释错误消息很棘手,实际上错误消息的不同部分很重要。请使用直接运行编译器的消息,而不是 IDE 生成的消息,它可能会尝试为您解释错误。

标签: for-loop rust hashmap ownership


【解决方案1】:

最简单的方法是让您的地图拥有密钥。这意味着您必须将其类型从HasMap&lt;&amp;str, i32&gt;(借用密钥)更改为HashMap&lt;String, i32&gt;。此时您可以调用to_string 将您的令牌转换为拥有的字符串:

let mut map: HashMap<String, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens:Vec<&str> = s.split(&d).collect();
    if tokens.len() > c {
        println!("{}", tokens[c]);
        let count = map.entry(tokens[c].to_string()).or_insert(0);
        *count += 1;
    }
}

但是请注意,这意味着 tokens[c] 将被复制,即使它已经存在于地图中。您可以先尝试使用get_mut 修改计数器来避免额外的重复,但这需要在缺少键时进行两次查找:

let mut map: HashMap<String, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens:Vec<&str> = s.split(&d).collect();
    if tokens.len() > c {
        println!("{}", tokens[c]);
        if let Some (count) = map.get_mut (tokens[c]) {
            *count += 1;
        } else {
            map.insert (tokens[c].to_string(), 1);
        }
    }
}

我不知道只有在没有先前条目时才复制密钥但仍进行单次查找的解决方案。

【讨论】:

  • 谢谢,当我将 HashMap 中的 Key 更改为 String 时,它可以工作。更改了 map.entry(),因此我在尝试解决它时发布的变体具有 map.entry(t)。后来改回map.entry(tokens[c].to_string())。
猜你喜欢
  • 1970-01-01
  • 2012-11-24
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
相关资源
最近更新 更多