Rust 借用检查器仅在返回具有相同生命周期的引用的函数时多次提示借用是可变的

标签 rust lifetime borrow-checker

我遇到了一些 Rust 代码的问题,在某些情况下我被允许多次借用可变的东西(第一个令人困惑的部分),但其他情况下则不行。

我写了下面的例子来说明: ( Playground )

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
}

如果你看到了,我可以多次借用 some_vallife_val 作为可变的。但是,给borrow_lifetime的返回值赋值后,我就不能再借了。

我的问题如下:

  1. 来自 Rust Book 中关于借款的“规则” ,我应该在范围内对相同的值有“恰好一个可变引用”。但是,在上面的代码中,每次调用 borrow_ 函数时,我都将借用为可变的。
  2. 为什么当我有一个函数返回与参数具有相同生命周期的东西时不允许相同类型的借用,并且我分配了那个参数。

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

最佳答案

Chris already gave the gist of it ,但我认为值得进一步解释。

在 Rust 中有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
}

调用函数时,借用参数:

  • 至少在函数调用期间
  • 直到结果被丢弃的那一刻,如果结果与参数共享生命周期

那么,让我们看看这个:

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

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

  • 在第 (8) 行调用 borrow_lifetime,它返回一个 &'a i32 并将结果分配num_again:结果与参数共享一个生命周期,因此参数被借用到 num_again 范围结束。

  • 在第 (9) 行你调用了 borrow_lifetime 但是它的参数仍然被 num_again 借用所以这个调用是非法的。

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


以后有电话non-lexical borrows .也就是说,编译器会意识到:

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

因此可以决定它的借用结束早于词法范围的结束。

关于Rust 借用检查器仅在返回具有相同生命周期的引用的函数时多次提示借用是可变的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38006421/

相关文章:

rust - 有没有办法传递对泛型函数的引用并返回与参数的生命周期无关的 impl Trait?

rust - 为什么 Rust 有 struct 和 enum?

generics - 我如何传达一个带有引用的泛型类型只需要通过函数调用生存?

c++ - 在析构函数中修改类成员对象是否会导致未定义的行为?

rust - 为不相关的顺序使用两次借用一个可变对象

Rust 不允许我从匹配中返回一个类型的实例,一直认为我正在尝试返回一个值

rust - "let MyStruct(x, y) = self;"有什么作用?为什么我可以访问 x 和 y?

rust - 关于理解生命周期的问题

methods - Rust 实现方法——在可变借用方法中使用 "getter"方法借用

rust - 不能在同一范围内的两个不同闭包内可变借用