Rust Borrow checker仅在返回具有相同生命周期分配的引用的函数时,多次抱怨多次借用mutable

cha*_*its 1 lifetime rust borrow-checker

我遇到一些Rust代码的问题,我被允许在某些条件下(第一个令人困惑的部分)不止一次地借用一些东西,而不是其他东西.

我写了下面的例子来说明:( 游乐场)

struct NoLifetime {}
struct WithLifetime <'a> {
    pub field: &'a i32
}

fn main() {
    let mut some_val = NoLifetime {};
    borrow_mut_function(&mut some_val);
    borrow_mut_function(&mut some_val); // Borrowing as mutable for the second time.

    let num = 5;
    let mut life_val = WithLifetime { field: &num };
    borrow_lifetime(&mut life_val);
    borrow_lifetime(&mut life_val); // Borrowing as mutable for the second time.

    let num_again = borrow_lifetime(&mut life_val); // Borrow, assign lifetime result
    borrow_lifetime(&mut life_val); // Compiler: cannot borrow `life_val` as mutable more than once
}

fn borrow_mut_function(val_in: &mut NoLifetime) -> String {
    "abc".to_string()
}
fn borrow_lifetime<'a>(val_in: &'a mut WithLifetime) -> &'a i32 {
    val_in.field
}
Run Code Online (Sandbox Code Playgroud)

如果你看到,我可以借两个some_val,并且life_val不止一次可变.但是,在分配了返回值之后borrow_lifetime,我再也无法借用了.

我的问题如下:

  1. 从关于在Rust书中借用的"规则"来看,我应该在范围内将"确切的一个可变引用"赋予相同的值.但是,在上面的代码中,每次调用borrow_函数时,我都是可变的.
  2. 当我的函数返回与参数具有相同生命周期的函数时,为什么不允许使用相同类型的借用,并且我分配了该参数.

任何帮助,将不胜感激.我想这里发生的事情是,我误解了"借用可变性"的真正含义,以及何时确定某些东西被借用为可变的东西.

Mat*_* M. 7

克里斯已经给出了它的要点,但我认为值得进一步解释.

2点的方式来鲁斯特转移所有权:

  • 移动永久转移
  • 借款临时转让,预计所有权归还

与许多其他语言一样,Rust使用一堆词法范围模拟时间传递.因此,现在,借用从创建它的地方开始,并延伸到其范围的末尾.


因此,借款何时结束的问题类似于询问借款的创造范围.

让我们用编号行来检查你的例子:

fn main() {
    let mut some_val = NoLifetime {};                // 1
    borrow_mut_function(&mut some_val);              // 2
    borrow_mut_function(&mut some_val);              // 3
                                                     // 
    let num = 5;                                     // 4
    let mut life_val = WithLifetime { field: &num }; // 5
    borrow_lifetime(&mut life_val);                  // 6
    borrow_lifetime(&mut life_val);                  // 7
                                                     //
    let num_again = borrow_lifetime(&mut life_val);  // 8
    borrow_lifetime(&mut life_val);                  // 9
}
Run Code Online (Sandbox Code Playgroud)

调用函数时,借用参数:

  • 至少在函数调用的持续时间内
  • 直到结果被删除的那一刻,如果结果与参数共享一个生命周期

那么,让我们来看看:

  • 在第(2)和(3)行中,您调用borrow_mut_function哪个返回String:结果不与参数共享任何生命周期,因此该参数仅在函数调用的生命周期内被借用.

  • 在第(6)和(7)行调用borrow_lifetime,它返回一个&'a i32:结果与参数共享一个生命周期,因此参数被借用直到结果范围的结尾...这是因为结果未被使用.

  • 在第(8)行,你调用borrow_lifetime哪个返回a &'a i32并将结果赋值num_again:结果与参数共享一个生命周期,因此参数被借用到范围的结尾num_again.

  • 在第(9)行,你打电话borrow_lifetime但它的论据仍然借用,num_again所以这个电话是非法的.

就是这样,这就是Rust今天的工作方式.


在未来,有一个非词汇借阅的呼吁.也就是说,编译器会意识到:

  • num_again 从未使用过
  • num_again没有特定的析构函数(没有Drop实现)

因此可以决定其借款的结束时间早于词汇范围的结束.


Chr*_*son 5

这是关于借款的范围,以及你是否保持借款.在大多数上述调用中,some_val在函数调用期间借用,但在函数返回后返回.

在例外情况下:

let num_again = borrow_lifetime(&mut life_val); //Borrow, assign lifetime result
Run Code Online (Sandbox Code Playgroud)

life_val在调用期间借用borrow_lifetime,但由于返回值与参数('a)具有相同的生命周期,因此借用范围将扩展为包括生命周期num_again,即直到函数结束.再借life_val一次是不安全的,因为num_again它仍然是对它的参考.