多重借用时的借用错误

3

我正在使用Rust实现一种就地递归解析器,并且我遇到了一些借用错误。下面的代码片段复现了这个问题,虽然它不是很有用。

 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);        
    }
}

这给了我以下错误:
错误[E0499]:一次不能将`my_vec`借为多个可变引用 --> test.rs:20:9 | 18 | let mut last : &mut Box = my_vec.last_mut().unwrap(); | ------ 第一次可变借用从这里开始 19 | let mut new_borrow = Box::new(MyBorrows::new(last.val)); 20 | my_vec.push(new_borrow); | ^^^^^^ 第二次可变借用从这里开始 21 | } 22 | } | - 第一次借用在这里结束
错误:由于之前的3个错误而中止
在我的实际情况中,这个向量被用作一个堆栈,以引用越来越深的struct组件。这是我在C++中用于通用解析的常见模式,我正在尝试在Rust中复制它,但我遇到了问题。任何帮助都将不胜感激。
1个回答

3
你试图做的事情是不合理的。看起来你正在尝试创建多个可变借用同一值的MyBorrows,并让它们同时存在于向量中。这种设置正是Rust旨在防止的,因为这就是数据竞争发生的原因。
你可能希望的是对该值进行多次不可变借用,这是合法的。因此,在清理不必要的可变借用之后,我将问题简化为:
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);
    }
}

现在可变借用在推入操作之前就结束了,生命周期得到了解决。希望将来我们能够获得非词法生命周期,这样编译器就可以确定我的第一个示例实际上是安全的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接