我有两个结构,Holder
和Held
。Holder
包含对Held
的引用。Held
持有i32
:
struct Holder<'a> {
val: &'a Held,
}
#[derive(Debug)]
struct Held(i32);
我想在名为holders
的Vec<_>
中创建 10 个Holder
秒。由于Holder
引用Held
结构,因此我还创建了一个名为heldvals
的Vec<_>
,它将存储main
函数作用域的Held
结构:
pub fn main() {
// contains the `Holder`s
let mut holders = vec![];
// contains the `Held`s
let mut heldvals = vec![];
for i in 0..10 {
heldvals.push(Held(i));
holders.push(Holder {
val: &heldvals.last().unwrap(),
});
}
}
当我尝试编译这个程序时,我收到一个错误:
error[E0502]: cannot borrow `heldvals` as mutable because it is also borrowed as immutable
|
| heldvals.push(Held(i));
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
| holders.push(Holder {
| ------- immutable borrow later used here
| val: &heldvals.last().unwrap(),
| -------- immutable borrow occurs here
作为一种解决方法,我不情愿地决定使用unsafe
,它可以正常工作,没有任何错误。我什至实现了Drop
特征来确认没有内存问题。
// ...
impl Drop for Held {
fn drop(&mut self) {
dbg!(self);
}
}
pub fn main() {
let mut holders = vec![];
let mut heldvals = vec![];
let hptr = &mut heldvals as *mut Vec<Held>;
for i in 0..10 {
println!("creation");
unsafe {
(*hptr).push(Held(i));
}
holders.push(Holder {
val: &heldvals.last().unwrap(),
});
println!("replacement");
}
}
运行上面的代码给出了这个(减少的)输出:
creation
replacement (10 times)
[src/main.rs:12] self = Held(
0,
)
...
[src/main.rs:12] self = Held(
9,
)
瓦尔格林德也没有显示内存泄漏或问题:
HEAP SUMMARY:
in use at exit: 0 bytes in 0 blocks
total heap usage: 18 allocs, 18 frees, 3,521 bytes allocated
All heap blocks were freed -- no leaks are possible
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
有没有办法避免使用unsafe
?我发现了Vec::reserve()
,这是个好主意吗?
不能借用为可变,因为它也被借用为不可变,其他类似的答案过于简单,无法解释循环和借用错误之间的关系。 此外,它们没有给出替代解决方案的指针。
使用参考计数器对我来说是不可能的。我想要一种简单的方法来保存引用,直到程序退出。
从我上面的回复中复制:
这里的基本内容是,一旦您重新更改heldvals
holders
就完全失效。因此,如果您完全填充heldvals
,然后循环访问它以填充holders
,那么您就可以了。但是一旦您再次更改heldvals
,holders
就会失效
#[derive(Debug)]
struct Holder<'a> {
val: &'a Held,
}
#[derive(Debug)]
struct Held(i32);
pub fn main() {
// contains the `Holder`s
let mut holders = vec![];
// contains the `Held`s
let mut heldvals = vec![];
for i in 0..10 {
heldvals.push(Held(i));
}
for i in 0..10 {
holders.push(Holder {
val: &heldvals[i],
});
}
for cur in holders.iter()
{
println!("cur: {:?}", cur);
}
// invalidate the holders
heldvals.push(Held(15));
println!("holders[1]: {:?}", holders[1])
}
这不会编译。 最后两行给出此错误:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `heldvals` as mutable because it is also borrowed as immutable
--> src/main.rs:29:5
|
21 | val: &heldvals[i],
| -------- immutable borrow occurs here
...
29 | heldvals.push(Held(15));
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
30 | println!("holders[1]: {:?}", holders[1])
| ------- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
但是删除这些行,它就可以了:
cur: Holder { val: Held(0) }
cur: Holder { val: Held(1) }
cur: Holder { val: Held(2) }
cur: Holder { val: Held(3) }
cur: Holder { val: Held(4) }
cur: Holder { val: Held(5) }
cur: Holder { val: Held(6) }
cur: Holder { val: Held(7) }
cur: Holder { val: Held(8) }
cur: Holder { val: Held(9) }
如上所述,这是因为您有两个可变变量,一旦您从第一个借用了可变变量,您将无法更改它,直到借用被"归还"。 一旦你从中借用了一些东西(或很多东西),你基本上就是在"锁定"第一个向量。 您不能同时构建heldvals
和holders
,也不能在借用heldvals
后对其进行更改。