首页 文章

在迭代向量时,如何改变向量中的另一个项,而不是向量本身?

提问于
浏览
4

对我来说很明显,迭代向量不应该让循环体任意地改变向量 . 这可以防止迭代器失效,这容易出错 .

但是,并非所有类型的突变都会导致迭代器失效 . 请参阅以下示例:

let mut my_vec: Vec<Vec<i32>> = vec![vec![1,2], vec![3,4], vec![5,6]];
for inner in my_vec.iter_mut() {        // <- or .iter()
    // ...
    my_vec[some_index].push(inner[0]);  // <-- ERROR
}

这样的突变不会使 my_vec 的迭代器无效,但是它是不允许的 . 它可以使 my_vec[some_index] 中对特定元素的任何引用无效,但我们仍然不使用任何此类引用 .

我知道这些问题很常见,我不是要求解释 . 我正在寻找一种方法来重构这个,以便我可以摆脱这个循环 . 在我的实际代码中,我有一个巨大的循环体,我不能模块化它,除非我很好地表达这一点 .

到目前为止我所想到的:

  • Rc<RefCell<...>> 包装矢量 . 我认为这仍然会在运行时失败,因为 RefCell 将由迭代器借用,然后当循环体尝试借用它时将失败 .

  • 使用临时向量累积未来推送,并在循环结束后推送它们 . 这没关系,但需要更多的分配而不是动态推送它们 .

  • 不安全的代码,并搞乱指针 .

  • Iterator documentation中列出的任何内容都无济于事 . 我检查了itertools,它看起来也没有帮助 .

  • 使用 while 循环和索引而不是使用迭代器来使用对外部向量的引用 . 这没关系,但不允许我使用迭代器和适配器 . 我只是想摆脱这个外循环并使用 my_vec.foreach(...) .

是否有任何成语或任何库可以让我很好地做到这一点不安全的功能可以,只要他们不暴露指针给我 .

2 回答

  • 3

    您可以将每个内部向量包装在 RefCell 中 .

    use std::cell::RefCell;
    
    fn main() {
        let my_vec : Vec<RefCell<Vec<i32>>> = vec![
            RefCell::new(vec![1,2]),
            RefCell::new(vec![3,4]),
            RefCell::new(vec![5,6])];
        for inner in my_vec.iter() {
            // ...
            let value = inner.borrow()[0];
            my_vec[some_index].borrow_mut().push(value);
        }
    }
    

    请注意,如果您需要能够推送到 inner 引用的向量,则此处的 value 绑定非常重要 . value 碰巧是一个没有't contain references (it'的类型,所以它没有工作 .

    如果我们写了 my_vec[some_index].borrow_mut().push(inner.borrow()[0]); ,那么两个借用都将一直有效,直到语句结束 . 如果 my_vec[some_index]inner 都引用相同的 RefCell<Vec<i32>> ,则会对 RefCell<T> already mutably borrowed 造成恐慌 .

  • 3

    在不更改 my_vec 的类型的情况下,您可以通过索引和split_at_mut简单地使用访问:

    for index in 0..my_vec.len() {
        let (first, second) = my_vec.split_at_mut(index);
    
        first[some_index].push(second[0]);
    }
    

    注意:请注意, second 中的索引由 index 关闭 .

    这是安全的,相对容易的,而且非常灵活 . 但是,它不适用于迭代器适配器 .

相关问题