为什么我不能连续两次调用一个可变方法(并存储结果)?

Cor*_*lks 4 rust

在以下示例中:

struct SimpleMemoryBank {
    vec: Vec<Box<i32>>,
}

impl SimpleMemoryBank {
    fn new() -> SimpleMemoryBank {
        SimpleMemoryBank{ vec: Vec::new() }
    }

    fn add(&mut self, value: i32) -> &mut i32 {
        self.vec.push(Box::new(value));
        let last = self.vec.len() - 1;
        &mut *self.vec[last]
    }
}

fn main() {
    let mut foo = SimpleMemoryBank::new();

    // Works okay
    foo.add(1);
    foo.add(2);

    // Doesn't work: "cannot borrow `foo` as mutable more than once at a time"
    let one = foo.add(1);
    let two = foo.add(2);
}
Run Code Online (Sandbox Code Playgroud)

add()可以连续多次调用,只要我不存储函数调用的结果.但是如果我存储函数(let one = ...)的结果,那么我得到错误:

problem.rs:26:15: 26:18 error: cannot borrow `foo` as mutable more than once at a time
problem.rs:26     let two = foo.add(2);
                            ^~~
problem.rs:25:15: 25:18 note: previous borrow of `foo` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends
problem.rs:25     let one = foo.add(1);
                            ^~~
problem.rs:27:2: 27:2 note: previous borrow ends here
problem.rs:17 fn main() {
...
problem.rs:27 }
              ^
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)

这是问题#6393的表现:借用范围不应该总是词汇吗?

我该如何解决这个问题?本质上,我想Box在向量中添加一个新的,然后返回对它的引用(这样调用者就可以使用它).

She*_*ter 9

这正是Rust旨在防止您造成的问题.如果您这样做会发生什么:

let one = foo.add(1);
foo.vec.clear();
println!("{}", one);
Run Code Online (Sandbox Code Playgroud)

或者如果foo.add通过在向量的开头推送新值来工作呢?坏事会发生!主要的是,当你借用一个变量时,你不能再改变变量了.如果你能够改变它,那么你可能会使借用的内存无效,然后你的程序可以做很多事情,最好的情况是它会崩溃.

这是问题#6393的表现:借用范围不应该总是词汇吗?

有点,但不是真的.在这个例子中,你永远不会使用onetwo,所以从理论上讲,非词法范围允许它编译.但是,你说

我想在向量中添加一个新的Box,然后返回对它的引用(这样调用者就可以使用它)

这意味着你真正想要的代码

let one = foo.add(1);
let two = foo.add(2);
do_something(one);
do_something(two);
Run Code Online (Sandbox Code Playgroud)

所以变量的生命周期会重叠.

在这种情况下,如果您只想要一个存储无法单独解除分配的变量的位置,请不要相互重叠,并且不能移动,请尝试使用TypedArena:

extern crate arena;

use arena::TypedArena;

fn main() {
    let arena = TypedArena::new();
    let one = arena.alloc(1);
    let two = arena.alloc(2);

    *one = 3;
    println!("{}, {}", one, two);
}
Run Code Online (Sandbox Code Playgroud)