我想删除BTreeMap
中通过迭代找到的项目。
由于迭代时无法删除项目,因此我将要删除的项目放入向量中。主要问题是不能使用引用的向量,而只能使用值向量。必须克隆必须删除条目的所有密钥(假设密钥实现了Clone
特征)。
例如,这个简短的示例无法编译:
use std::collections::BTreeMap;
pub fn clean() {
let mut map = BTreeMap::<String, i32>::new();
let mut to_delete = Vec::new();
{
for (k, v) in map.iter() {
if *v > 10 {
to_delete.push(k);
}
}
}
for k in to_delete.drain(..) {
map.remove(k);
}
}
fn main() {}
编译时会产生以下错误:
error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
--> src/main.rs:17:9
|
9 | for (k, v) in map.iter() {
| --- immutable borrow occurs here
...
17 | map.remove(k);
| ^^^ mutable borrow occurs here
18 | }
19 | }
| - immutable borrow ends here
使用to_delete.push(k)
更改to_delete.push(k.clone())
会使此代码段正确编译,但如果必须克隆要删除的每个密钥,则代价非常高。
有更好的解决方案吗?
答案 0 :(得分:3)
TL; DR:你不能。
就编译器而言,BTreeMap::remove
的实现可能会这样做:
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Ord + ?Sized,
{
// actual deleting code, which destroys the value in the set
// now what `value` pointed to is gone and `value` points to invalid memory
// And now we access that memory, causing undefined behavior
key.borrow();
}
因此,编译器必须防止在集合发生变异时使用对值的引用。
要做到这一点,你需要像假设的光标&#34;集合的API。这将允许您遍历集合,返回一个特殊类型,其中包含集合的可变内部。此类型可以为您提供检查的参考,然后允许您删除该项目。
我可能从一个不同的方向看问题。我没有试图保留地图,而是创造了一个全新的地图:
use std::collections::BTreeMap;
pub fn main() {
let mut map = BTreeMap::new();
map.insert("thief", 5);
map.insert("troll", 52);
map.insert("gnome", 7);
let map: BTreeMap<_, _> =
map.into_iter()
.filter(|&(_, v)| v <= 10)
.collect();
println!("{:?}", map); // troll is gone
}
如果您的条件在使结构唯一的字段上相等(也就是PartialEq
和Hash
中使用的唯一字段),则可以实现{{1对于你的类型,直接抓住/删除它:
Borrow
另见: