gpt4 book ai didi

rust - 从通过迭代找到的 BTreeMap 或 BTreeSet 中删除项目

转载 作者:行者123 更新时间:2023-11-29 08:32:29 26 4
gpt4 key购买 nike

我想从 BTreeMap 中删除通过迭代找到的项目。

由于无法在迭代时删除项目,我将要删除的项目放入一个向量中。主要问题是不可能使用引用 向量,而只能使用值向量。然后必须克隆所有必须删除条目的 key (假设 key 实现了 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()) 可使此代码段正确编译,但如果要删除每个键,成本会很高必须克隆。

有没有更好的解决方案?

最佳答案

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();
}

因此,当集合发生变化时,编译器必须阻止使用对值的引用。

为此,您需要类似假设的集合“游标”API 之类的东西。这将允许您遍历集合,返回一个特殊类型来保存集合的可变内部结构。这种类型可以为您提供引用以进行检查,然后允许您删除该项目。


我可能会从不同的角度看待这个问题。我不想保留 map ,而是创建一个全新的 map :

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
}

如果您的条件在使结构唯一的字段上相等(也就是 PartialEqHash 中使用的唯一字段),您可以为您的类型实现 Borrow 并直接抓取它/删除它:

use std::collections::BTreeMap;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Monster(String);

use std::borrow::Borrow;

impl Borrow<str> for Monster {
fn borrow(&self) -> &str { &self.0 }
}

pub fn main() {
let mut map = BTreeMap::new();

map.insert(Monster("thief".into()), 5);
map.insert(Monster("troll".into()), 52);
map.insert(Monster("gnome".into()), 7);

map.remove("troll");

println!("{:?}", map); // troll is gone
}

另见:

关于rust - 从通过迭代找到的 BTreeMap 或 BTreeSet 中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51290687/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com