可变借款不止一次

时间:2018-03-02 10:32:54

标签: rust

这是一个简短的示例,不能编译。错误发生在add1函数中。如果我在add2中这样做,它会起作用,但这不是很干。有经验的人可以告诉我如何以比add2更好的方式克服可变借用不止一次的错误。

struct S1 {
    full: bool,
    v: Vec<u32>,
}

struct S2 {
    v: Vec<S1>,
}

impl S2 {
    // If last is not full push n to last.v, otherwise push a new S1

    // Doesn't work
    fn add1(&mut self, n: u32) {
        // Let's assume it's not empty
        let s1 = self.v.last_mut().unwrap();
        if !s1.full {
            s1.v.push(n);
        } else {
            self.v.push(S1 {
                full: false,
                v: vec![n],
            });
        }
    }

    // Works
    fn add2(&mut self, n: u32) {
        // First getting last as immutable ref and then as mutable ref
        let full = self.v.last().unwrap().full;
        if !full {
            self.v.last_mut().unwrap().v.push(n);
        } else {
            self.v.push(S1 {
                full: false,
                v: vec![n],
            });
        }
    }
}

fn main() {}

playground

编译错误:

error[E0499]: cannot borrow `self.v` as mutable more than once at a time
  --> src/main.rs:20:13
   |
16 |         let s1 = self.v.last_mut().unwrap();
   |                  ------ first mutable borrow occurs here
...
20 |             self.v.push(S1 {
   |             ^^^^^^ second mutable borrow occurs here
...
25 |     }
   |     - first borrow ends here

2 个答案:

答案 0 :(得分:3)

您有两种选择。

1)每晚使用并将#![feature(nll)]放在文件的顶部。

非词汇生命周期正好解决了这个问题:即使{else}块中没有使用s1借用,它仍然存活并阻止self.v的变异。对于非词汇生命周期,编译器会认识到s1实际上已经死了,让你再次借用。

2)像这样构建你的代码:

fn add1(&mut self, n: u32) {
    { // add a scope around s1 so that it disappears later
        let s1 = self.v.last_mut().unwrap();
        if !s1.full {
            s1.v.push(n);
            return; // just return early instead of using else
        }
    }
    self.v.push(S1 {
        full: false,
        v: vec![n]
    });
}

答案 1 :(得分:0)

您可以限制重复:

fn add1(&mut self, n: u32) {
    // Let's assume it's not empty
    if {
        let s1 = self.v.last_mut().unwrap();
        if !s1.full {
            s1.v.push(n);
        }
        s1.full
    } {
        self.v.push(S1 {
            full: false,
            v: vec![n],
        });
    }
}

playground