我有一个使用四叉树的程序.此树存储对另一个容器(VEC)拥有的数据的可变borrow .我重建四叉树每个游戏循环,但我不想重新分配,所以我clear
的基础VEC的四叉树,而不是从头开始重建它.
下面显示了一个演示相同问题的简化示例.这里我使用的不是QuadTree,而是另一个VEC,因为它有相同的问题.
struct A;
fn main() {
let mut owned_data = vec![A, A, A];
let mut mut_borrowed_data = vec![];
'_outer: loop {
mut_borrowed_data.clear();
'_inner: for borrow in &mut owned_data {
mut_borrowed_data.push(borrow);
}
}
}
这会产生错误:
error[E0499]: cannot borrow `owned_data` as mutable more than once at a time
--> src\main.rs:8:30
|
8 | '_inner: for borrow in &mut owned_data {
| ^^^^^^^^^^^^^^^ `owned_data` was mutably borrowed here in the previous iteration of the loop
问题其实并不在于我是在悄悄地borrow 外部循环的前一个迭代.如果我删除它编译的mut_borrowed_data.push(data);
,因为借入判断器意识到owned_data
的可变借入在每个外部循环的末尾被丢弃,因此可变借入的数量是最大值1.通过压入mut_borrowed_data
,这个可变借入是moved进入这个容器(如果我错了请纠正我),因此它不会被丢弃并且借入判断器不高兴.如果我没有clear
,就会有可变借入的多个副本,并且借入判断器不够聪明,无法意识到我只推入mut_borrowed_data
一次,而我clear
每个外循环都是clear
.
但是按照现在的情况,任何时候都只有一个可变借入的实例,那么下面的代码安全吗?
struct A;
fn main() {
let mut owned_data = vec![A, A, A];
let mut mut_borrowed_data = vec![];
'_outer: loop {
mut_borrowed_data.clear();
'_inner: for borrow in &mut owned_data {
let ptr = borrow as *mut A;
let new_borrow = unsafe { &mut *ptr };
mut_borrowed_data.push(new_borrow);
}
}
}
现在可以编译这段代码.可变借位owned_data
(名为borrow
)不会移到mut_borrowed_data
中,因此它会在外部循环的末尾被丢弃.这意味着owned_data
只是可变的借来一次.不安全代码takes a copy of the pointer to the data, dereferences it and creates a new borrow to that.(同样,如果我错了,请纠正我).因为这使用的是复制而不是移动,所以编译器允许borrow
和new_borrow
同时存在.使用unSafe可能会违反borrow 规则,但只要我在创建new_borrow
之后不使用borrow
,并且只要我清除了mut_borrowed_data
,那么我认为这是安全的.
此外,(我认为)借款判断员提供的担保仍然有效as long as I clear the mut_borrowed_data vec.它不会让我在一个循环中两次推入mut_borrowed_data
,因为new_borrow
在第一次插入后会移动.
我不想使用RefCell
,因为我想让它尽可能地有性能.QuadTree的全部目的是提高性能,所以我想使它引入的任何开销都尽可能地精简.递增借入计数可能很便宜,但分支(判断该值是否为<;=1)、间接性以及数据简单性的降低让我无法感到高兴.
我在这里使用不安全的词安全吗?有没有什么事会让我绊倒?