Rust 从通过迭代找到的BTreeMap或BTreeSet中删除项

Rust 从通过迭代找到的BTreeMap或BTreeSet中删除项,rust,Rust,我想从BTreeMap中删除通过迭代找到的项目 由于迭代时无法删除项,因此我将要删除的项放入一个向量中。主要问题是不可能使用参考向量,而只能使用值向量。然后必须克隆必须删除其条目的所有键(假设该键实现了克隆特征) 例如,此简短示例不编译: use std::collections::BTreeMap; pub fn clean() { let mut map = BTreeMap::<String, i32>::new(); let mut to_delete =

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

由于迭代时无法删除项,因此我将要删除的项放入一个向量中。主要问题是不可能使用参考向量,而只能使用值向量。然后必须克隆必须删除其条目的所有键(假设该键实现了
克隆
特征)

例如,此简短示例不编译:

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() {}
更改为_delete.push(k)
并将
更改为_delete.push(k.clone())
可以正确编译此代码段,但如果必须克隆每个要删除的键,则成本相当高

有更好的解决方案吗?

TL;医生:你不能

就编译器而言,的实现可能会做到这一点:

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


我希望最终,
BTreeMap
能够获得类似于
fn drain(&mut self,Range)
的方法。“相关的是,但也要检查一下,”@Shepmaster——当然,这里的问题是它不是范围,而是范围Range@Jsor啊,我错过了。我觉得这不太可能,所以这确实是一个棘手的问题!这里需要的是一个版本的
drain
使用谓词,这确实是一个值得添加的内容。这是一个有趣的想法。请注意,根据映射的大小和要删除的元素的数量,这在性能方面不是一个明显的增益。
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
}
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
}