我很清楚,迭代向量不应该让循环体任意改变向量。这可以防止迭代器失效,从而容易出现错误。
然而,并非所有类型的突变都会导致迭代器失效。请参见以下示例:
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文档没有帮助。我结帐了迭代工具看起来也没有帮助。
- Using a
while
循环和索引,而不是使用迭代器,利用对外部向量的引用。这没关系,但不允许我使用迭代器和适配器。我只是想摆脱这个外循环并使用my_vec.foreach(...)
.
是否有任何习惯用法或任何库可以让我很好地完成此操作,只要不向我公开指针,不安全函数就可以。
您可以将每个内部向量包装在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);
}
}
请注意,value
如果您需要能够推送到向量,那么这里的绑定很重要inner
指。value
恰好是一个不包含引用的类型(它是i32
),因此它不会使第一个借用保持活动状态(它在语句末尾结束)。然后,下一个语句可以可变地借用相同的向量或另一个向量,并且它会起作用。
如果我们写my_vec[some_index].borrow_mut().push(inner.borrow()[0]);
相反,两个借用都将一直有效,直到语句结束。如果两者都my_vec[some_index]
and inner
参考相同的RefCell<Vec<i32>>
,这会引起恐慌RefCell<T> already mutably borrowed
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)