如何处理 HashMap 中的每个值并选择性地拒绝某些值?
How to process every value in a HashMap and optionally reject some?
我想一个一个地处理 HashMap
中的值,同时可能会删除其中的一些值。
例如,我想做一个相当于:
use std::collections::HashMap;
fn example() {
let mut to_process = HashMap::new();
to_process.insert(1, true);
loop {
// get an arbitrary element
let ans = to_process.iter().next().clone(); // get an item from the hash
match ans {
Some((k, v)) => {
if condition(&k,&v) {
to_process.remove(&k);
}
}
None => break, // work finished
}
}
}
但是编译失败:
error[E0502]: cannot borrow `to_process` as mutable because it is also borrowed as immutable
--> src/lib.rs:12:17
|
9 | let ans = to_process.iter().next().clone();
| ---------- immutable borrow occurs here
...
12 | to_process.remove(&k);
| ^^^^^^^^^^^------^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
我知道我真的需要 https://github.com/rust-lang/rust/issues/27804(这是 HashSet
但 HashMap
是一样的)
如果没有非可变和可变引用或使用不安全,我将无法实施所提供的解决方案。
有没有我遗漏的简单方法?
这看起来非常适合 Iterator::filter_map
:
The closure must return an Option<T>
. filter_map
creates an iterator which calls this closure on each element. If the closure returns Some(element)
, then that element is returned. If the closure returns None
, it will try again, and call the closure on the next element, seeing if it will return Some
.
下面的process_and_maybe_add
很简单,但是你明白了:
use std::collections::HashMap;
fn main() {
let mut data = HashMap::new();
data.insert(1, "a");
data.insert(2, "b");
data.insert(3, "c");
let processed = data
.into_iter()
.filter_map(process_and_maybe_add)
.collect::<HashMap<_, _>>();
dbg!(processed);
}
fn process_and_maybe_add((k, v): (u32, &str)) -> Option<(u32, String)> {
if k % 2 != 0 {
Some((k + 100, v.to_owned() + v))
} else {
None
}
}
注意 如果您需要在处理过程中更改密钥或向 HashMap
添加 kvps,请参阅@edwardw 的回答。否则...
使用HashMap::retain
。您可以将处理函数更改为 return a bool
以指示是否保留该键值对。例如
let mut to_process: HashMap<u32, String> = HashMap::new();
to_process.insert(1, "ok".to_string());
to_process.insert(2, "bad".to_string());
to_process.retain(process);
fn process(k: &u32, v: &mut String) -> bool {
// do stuff with k and v
v == "ok"
}
我想一个一个地处理 HashMap
中的值,同时可能会删除其中的一些值。
例如,我想做一个相当于:
use std::collections::HashMap;
fn example() {
let mut to_process = HashMap::new();
to_process.insert(1, true);
loop {
// get an arbitrary element
let ans = to_process.iter().next().clone(); // get an item from the hash
match ans {
Some((k, v)) => {
if condition(&k,&v) {
to_process.remove(&k);
}
}
None => break, // work finished
}
}
}
但是编译失败:
error[E0502]: cannot borrow `to_process` as mutable because it is also borrowed as immutable
--> src/lib.rs:12:17
|
9 | let ans = to_process.iter().next().clone();
| ---------- immutable borrow occurs here
...
12 | to_process.remove(&k);
| ^^^^^^^^^^^------^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
我知道我真的需要 https://github.com/rust-lang/rust/issues/27804(这是 HashSet
但 HashMap
是一样的)
如果没有非可变和可变引用或使用不安全,我将无法实施所提供的解决方案。
有没有我遗漏的简单方法?
这看起来非常适合 Iterator::filter_map
:
The closure must return an
Option<T>
.filter_map
creates an iterator which calls this closure on each element. If the closure returnsSome(element)
, then that element is returned. If the closure returnsNone
, it will try again, and call the closure on the next element, seeing if it will returnSome
.
下面的process_and_maybe_add
很简单,但是你明白了:
use std::collections::HashMap;
fn main() {
let mut data = HashMap::new();
data.insert(1, "a");
data.insert(2, "b");
data.insert(3, "c");
let processed = data
.into_iter()
.filter_map(process_and_maybe_add)
.collect::<HashMap<_, _>>();
dbg!(processed);
}
fn process_and_maybe_add((k, v): (u32, &str)) -> Option<(u32, String)> {
if k % 2 != 0 {
Some((k + 100, v.to_owned() + v))
} else {
None
}
}
注意 如果您需要在处理过程中更改密钥或向 HashMap
添加 kvps,请参阅@edwardw 的回答。否则...
使用HashMap::retain
。您可以将处理函数更改为 return a bool
以指示是否保留该键值对。例如
let mut to_process: HashMap<u32, String> = HashMap::new();
to_process.insert(1, "ok".to_string());
to_process.insert(2, "bad".to_string());
to_process.retain(process);
fn process(k: &u32, v: &mut String) -> bool {
// do stuff with k and v
v == "ok"
}