cfl*_*wis 16 rust borrow-checker
我正在尝试编写一些玩具代码,用于存储它在一个单词中看到单词的次数HashMap.如果密钥存在,则将计数器递增1,如果密钥不存在,则将其与值相加1.我本能地希望用模式匹配来做这个,但是我不止一次地尝试了一个可变的错误:
fn read_file(name: &str) -> io::Result<HashMap<String, i32>> {
let b = BufReader::new(File::open(name)?);
let mut c = HashMap::new();
for line in b.lines() {
let line = line?;
for word in line.split(" ") {
match c.get_mut(word) {
Some(i) => {
*i += 1;
},
None => {
c.insert(word.to_string(), 1);
}
}
}
}
Ok(c)
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
error[E0499]: cannot borrow `c` as mutable more than once at a time
--> <anon>:21:21
|
16 | match c.get_mut(word) {
| - first mutable borrow occurs here
...
21 | c.insert(word.to_string(), 1);
| ^ second mutable borrow occurs here
22 | }
23 | }
| - first borrow ends here
Run Code Online (Sandbox Code Playgroud)
我理解为什么编译器脾气暴躁:我告诉它我要改变键入的值word,但是插入不是那个值.但是,插入是在a上None,所以我原以为编译器可能已经意识到现在没有机会进行变异c[s].
我觉得这种方法应该有效,但我错过了一个技巧.我究竟做错了什么?
编辑:我意识到我可以使用
if c.contains_key(word) {
if let Some(i) = c.get_mut(s) {
*i += 1;
}
} else {
c.insert(word.to_string(), 1);
}
Run Code Online (Sandbox Code Playgroud)
但这似乎是非常难看的代码与模式匹配(特别是必须将contains_key()检查作为if,然后基本上再次使用Some.
eul*_*isk 13
您必须使用条目"模式":
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
fn main() {
let mut words = vec!["word1".to_string(), "word2".to_string(), "word1".to_string(), "word3".to_string()];
let mut wordCount = HashMap::<String, u32>::new();
for w in words {
let val = match wordCount.entry(w) {
Vacant(entry) => entry.insert(0),
Occupied(entry) => entry.into_mut(),
};
// do stuff with the value
*val += 1;
}
for k in wordCount.iter() {
println!("{:?}", k);
}
}
Run Code Online (Sandbox Code Playgroud)
Entry对象允许您在缺少值时插入值,或者如果值已经存在则进行修改.
https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html
A.B*_*.B. 12
HashMap::entry()是这里使用的方法.在大多数情况下,您希望使用with Entry::or_insert()来插入值:
for word in line.split(" ") {
*c.entry(word).or_insert(0) += 1;
}
Run Code Online (Sandbox Code Playgroud)
如果要插入的值需要昂贵地计算,您可以使用Entry::or_insert_with()以确保计算仅在需要时执行.这两种or_insert方法都可能涵盖您的所有需求.但是,如果你出于某种原因想要做别的事情,你仍然可以简单地match在Entry枚举上.
| 归档时间: |
|
| 查看次数: |
2109 次 |
| 最近记录: |