Rust 重借用

目录

重借用

可知 Rust 的不能同时有两个以上, 那么如下情况会有矛盾:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn increase(cnt: &mut i32) {
    *cnt += 10;
}

fn main() {
    let mut cnt = 10;
    let cnt_ref = &mut cnt;

    // do something

    increase(cnt_ref);    // 同时有两个以上的可变引用?
    increase(cnt_ref);
    println!("{}", cnt_ref);
}

上面情况在实现应用中, 应该会出现。那么 Rust 给出了 “重借用 (reborrowing)” 的概念来允许这种情况:

  • 相当于, 调用 increase 时, 重新创建于一个新的可变引用, 但仅在函数调用期间有效。函数返回后,原来的可变引用会变得有效。

重借用的概念十分复杂, 官方文档都没有详细的解析:

当编译器知道引用的类型时, 就会发生重借用的情况。

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn main() {
    let mut v = vec![1, 2, 3];
    let foo = &mut v;
    let bar = &mut *foo;                // 重借用, foo 临时移动到 bar, bar 生命周期结束后会归回。
    //let bar = foo;                      // 不是重借用, 是 move, 不会自动归回。
    //let bar: &mut Vec<i32> = foo;       // 编译器知道类型会发生重借用
    //let bar: &mut _ = foo;              // 不指明类型也会发生重借用

    //foo.push(3);                        // error: second mutable borrow occurs here. 重借用也不能发生两次可变借用。
    bar.push(4);
    foo.push(5);                        // 重借用不是 move, bar 的生命周期结束后, 会归回, 而 move 不会。
}

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn bar<T>(_a: T, _b: T) {}

fn main() {
    let mut i = 42;
    let mut j = 43;
    let x = &mut i;
    let y = &mut j;
    bar(x, y);   // Moves x, but reborrows y.
                 // 首先是推导模板参数, 所以编译器不知道第一个参数的类型, 推导出类型后, 第二个参数类型知道了。
    let _z = x;  // error[E0382]: use of moved value: `x`
    let _t = y;  // Works fine. 
}

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
struct X;

trait Foo: Sized {
    fn foo(self) {}         // let self = <param>
}

impl Foo for &mut X {}

fn main() {
    let x: &mut X = &mut X;
    x.foo();
    x.foo(); // Reborrows x

    let x: &mut X = &mut X;
    Foo::foo(x);
    Foo::foo(x); // Doesn't reborrow x, fails to compile
}
0%