Rust 如何修改/部分删除BTreeMap中的范围?
我正在尝试从一个Rust 如何修改/部分删除BTreeMap中的范围?,rust,Rust,我正在尝试从一个BTreeMap(其中键是下界,值是上界)构建一个范围集。只要我只是在查找资料,这个方法就可以很好地工作。然而,第一种变异方法让我感到困惑: 如果我想在我的集合中插入一个范围,我需要从尾部到头部的范围的上限检查我的BTreeMap的range,直到所讨论的值低于插入范围的下限,所有包含的范围都应该被删除并合并重叠范围。但是,即使使用当前不稳定的.range\u mut(..),我也找不到删除条目的方法(因为地图仍然是由range借用的) 我用错工具了吗?我可以让它工作吗?如果可以
BTreeMap
(其中键是下界,值是上界)构建一个范围集。只要我只是在查找资料,这个方法就可以很好地工作。然而,第一种变异方法让我感到困惑:
如果我想在我的集合中插入一个范围,我需要从尾部到头部的范围的上限检查我的BTreeMap
的range
,直到所讨论的值低于插入范围的下限,所有包含的范围都应该被删除并合并重叠范围。但是,即使使用当前不稳定的.range\u mut(..)
,我也找不到删除条目的方法(因为地图仍然是由range借用的)
我用错工具了吗?我可以让它工作吗?如果可以,怎么做?我当前的伪代码解决方案(我也使用我自己的Cut
类型,因为Bound
s不是Ord
):
fn插入(&mut self,范围:&range){
用于self.map.range_mut(Cut::Unbounded,range.upper.rev()中的条目{
如果条目.1范围.lower{
删除条目
}否则{
将条目与范围合并
}
}
}
您需要分两次执行此操作,收集要删除的密钥,然后迭代该列表并调用remove
请注意,由于在遍历树时会得到引用,因此必须克隆/复制该键,因为在映射中会有一个对键的引用,这意味着您不能将映射作为可变对象借用
<>这主要是因为内存和排序语义在迭代中间删除条目时有点不正常。在遍历树时删除树中的条目是相当困难的。这是一个映射,这意味着关键点在树中以某种方式排序,这意味着节点可能会旋转其子节点,因此您可能以前访问过您的左子节点,现在突然成为您的当前节点或右子节点。很难知道你在哪里
此外,B-树节点是子节点的列表,当节点需要合并和拆分时,它们具有动态性,在迭代的过程中,这样做更令人头痛。
其中一些原因是由于手动内存语义。键和值存储在节点中,而不是堆上,因此内存将到处弹跳,确保它不会失效是非常重要的。尤其是当用户正在收集对循环中其他位置的树中条目的引用时
编辑:不管可能性如何,事实是迭代器借用了映射,这意味着你不能再借用它来删除东西。如果迭代器返回类似于条目的内容,这可能会有所不同,但据我所知,没有迭代器存在这种情况。如果真的不可能一次完成,为什么Java可以这样做?他们的迭代器有一个.remove()
方法来删除当前条目。我认为应该可以在Rust的std::collection中创建一个类似的选项(可能通过一个产生OccupiedEntryIterator)crate@llogiq迭代器的东西,你可以整理出来,即使它不是有趣的。内存语义要困难得多。Java通过让所有内容都是指针来避免这种情况。考虑一棵树,我有一个A的参考,然后我删除B和一个动作,那现在的参考点是什么?在Java中,答案与堆中的位置相同。在《铁锈》中,答案是“死的记忆”。(这有点不准确,因为Java确实在做一些类似于克隆Rc
的事情,但却能理解要点)是的,但我们的迭代器可以可变地借用BTree并使用泄漏放大(基本上是交换掉树,因此如果迭代器没有被删除,其他人将看到一个连贯的空树)确保死引用保持这种状态。
fn insert(&mut self, range: &Range) {
for entry in self.map.range_mut(Cut::Unbounded, range.upper).rev() {
if entry.1 < range.lower {
break;
} else if entry.0 > range.lower {
delete entry
} else {
merge entry with range
}
}
}