我正在尝试将我在C ++中使用的一些简单数据结构转换为Rust,从区间树开始,但我不明白如何修改我的基础数据结构(此处为std::collections::BTreeSet
)迭代 - 基本上我可以合并重叠的条目。
如果我使用标准习惯用于迭代集合,我得到以下消息:它不可变“不能借用self.storage
作为可变因为它也被借用为不可变的”,并且似乎没有得到一个我可以看到的可变迭代器的选项......我错过了什么?
C ++代码:
inline void Insert(const Interval& interval)
{
auto it = storage.insert(interval);
// check to see if we overlap the previous element,
// if we do, start our merge loop from there
if (it != begin()) {
const_iterator prev = std::prev(it);
if (prev->Overlaps(*it)) it = prev;
}
while (it != end()) {
const_iterator nx = std::next(it);
if (nx != end() && it->Overlaps(*nx)) {
const Interval u = it->Union(*nx);
it = storage.erase(it);
it = storage.erase(it);
it = storage.insert(it, u);
} else
break;
}
}
Rust代码:
/// Add a new interval into the tree
pub fn insert(&mut self, other: Interval) -> () {
self.storage.insert(other);
for int in self.storage.iter() {
if other <= *int {
break
} else if other.overlaps(int) {
self.storage.remove(&other);
self.storage.remove(int);
self.storage.insert(other.union(int).unwrap());
}
}
}
答案 0 :(得分:3)
当你迭代它时,你不能改变BTreeSet
- 这会使迭代器失效。不幸的是,与C ++不同,Rust没有返回更新迭代器的insert
或remove
方法(如果有的话,它们必须是迭代器本身的方法)。
BTreeSet
不提供可变迭代器,因为您可以做的唯一额外操作是获取对集合中元素的可变引用。但是,这样做可能会破坏集合的顺序,因此无法使用。
最直接的解决方案是构建在迭代期间执行的操作列表,然后在迭代完成后执行它们。但是,对于此算法,这将无法正常工作,因为您可能需要合并作为上一次合并结果的间隔。因此,一旦找到要合并的一对间隔,就需要跟踪相关值,突破迭代,执行合并,然后重新开始迭代。 BTreeSet
提供了一个range
方法,可让您迭代集合值的子集,因此您可能希望使用该方法而不是iter
,它始终迭代所有值。但是,从Rust 1.8开始,range
不稳定,所以你需要一个夜间编译器才能使用它。