为什么当我保留对附加到循环内的向量中的元素的引用时,借用检查器会引发错误?
Why does the borrow checker raise an error when I keep a reference to an element in a vector that is appended to within a loop?
我有两个结构,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<_>
来存储 [=30= 范围内的 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,
)
Valgrind 未显示内存泄漏或问题:
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
。
我有两个结构,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<_>
来存储 [=30= 范围内的 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,
)
Valgrind 未显示内存泄漏或问题:
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
。