我正在实现一个生锈的就地递归解析器,我得到一些借用错误。代码片段再现了问题,尽管它不是很有用
use std::vec::Vec;
struct MyBorrows<'a> {
val : &'a mut i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a mut i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let mut my_val = 23;
let mut my_vec : Vec<Box<MyBorrows>> = Vec::new();
my_vec.push(Box::new(MyBorrows::new(&mut my_val)));
for i in [1..4].iter() {
let mut last : &mut Box<MyBorrows> = my_vec.last_mut().unwrap();
let mut new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
这给了我以下错误:
error[E0499]: cannot borrow `my_vec` as mutable more than once at a time --> test.rs:20:9 | 18 | let mut last : &mut Box = my_vec.last_mut().unwrap(); | ------ first mutable borrow occurs here 19 | let mut new_borrow = Box::new(MyBorrows::new(last.val)); 20 | my_vec.push(new_borrow); | ^^^^^^ second mutable borrow occurs here 21 | } 22 | } | - first borrow ends here error: aborting due to 3 previous errors
在我的实际情况中,向量用作堆栈来引用我正在解析的struct
的更深和更深的组件。这是我在C ++中用于通用解析的常见模式,我试图在Rust中复制但是我遇到了问题。任何帮助将不胜感激。
答案 0 :(得分:3)
你要做的事情是不健全的。看起来你正在尝试创建多个MyBorrows
,它们都可以相互借用相同的值,并让它们一次存活(在向量中)。这样的设置正是Rust旨在防止的,因为这就是数据竞争的发生方式。
您可能想要做的是 im 可变地借用一堆价值,这是合法的。因此,在清理了不必要的可变借词之后,我将问题简化为:
struct MyBorrows<'a> {
val : &'a i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let last = my_vec.last().unwrap();
let new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
现在你的错误略有不同:
error[E0502]: cannot borrow `my_vec` as mutable because it is also borrowed as immutable
--> test.rs:18:9
|
16 | let last = my_vec.last().unwrap();
| ------ immutable borrow occurs here
17 | let new_borrow = Box::new(MyBorrows::new(last.val));
18 | my_vec.push(new_borrow);
| ^^^^^^ mutable borrow occurs here
19 | }
| - immutable borrow ends here
error: aborting due to previous error
这个比较棘手,当你致电my_vec.last()
时,你必须意识到发生了什么 - 它正在返回对Vec中现有记忆的引用,从而排除了接触Vec的任何其他内容。目前在Rust中,此引用一直持续到当前块的结尾。为了解决这个问题,请将可变借用包含在自己的块范围内:
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let new_borrow;
{
let last = my_vec.last().unwrap();
new_borrow = Box::new(MyBorrows::new(last.val));
}
my_vec.push(new_borrow);
}
}
现在,可变借用在推送发生之前结束,并且生命周期起作用。希望将来we will get non-lexical lifetimes添加到语言中,因此编译器可以确定我的第一个示例实际上是安全的。