在迭代期间修改对象

时间:2016-05-21 20:54:05

标签: iterator rust mutable

我正在尝试将我在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());
        }
    }
}

1 个答案:

答案 0 :(得分:3)

当你迭代它时,你不能改变BTreeSet - 这会使迭代器失效。不幸的是,与C ++不同,Rust没有返回更新迭代器的insertremove方法(如果有的话,它们必须是迭代器本身的方法)。

BTreeSet不提供可变迭代器,因为您可以做的唯一额外操作是获取对集合中元素的可变引用。但是,这样做可能会破坏集合的顺序,因此无法使用。

最直接的解决方案是构建在迭代期间执行的操作列表,然后在迭代完成后执行它们。但是,对于此算法,这将无法正常工作,因为您可能需要合并作为上一次合并结果的间隔。因此,一旦找到要合并的一对间隔,就需要跟踪相关值,突破迭代,执行合并,然后重新开始迭代。 BTreeSet提供了一个range方法,可让您迭代集合值的子集,因此您可能希望使用该方法而不是iter,它始终迭代所有值。但是,从Rust 1.8开始,range不稳定,所以你需要一个夜间编译器才能使用它。