为什么我可以使用可变变量,使其生命周期与不可变引用重叠,但我不能以相同的方式使用可变引用?

Why can I use a mutable variable such that its lifetime overlaps with an immutable reference, but I can't use a mutable reference in the same way?

我不明白为什么借用检查器允许可变变量的生命周期与不可变引用的生命周期重叠,但不允许可变的引用的生命周期与不可变引用的生命周期重叠。

这样编译:

let mut s = String::from("hello"); // some warning about s not needing to be mutable
let r = &s;
println!("{}, {}", r, s);

但这不是:

let mut s = String::from("hello");
let r_mut = &mut s; // mutable borrow here
let r = &s; // immutable borrow here
println!("{}, and {}", r, r_mut); // mutable borrow used here, error

为什么我可以以不可变的方式使用可变变量,使其生命周期与不可变引用重叠,但我不能使用可变引用以同样不变的方式?

让我们先更正一下术语。

变量绑定没有生命周期。他们有一个范围。当变量绑定超出范围时,它绑定的对象将被删除。这种行为不受借用检查器的控制。范围是词法的,在查看源代码时很容易看到。

借用是有生命周期的。这些生命周期将由借用检查器推断出来,并且它们与代码的词​​法结构 ("non-lexical lifetimes") 无关,尽管它们过去是这样。生命周期大致从创建借用的点延伸到最后使用它的点。

当您创建一个变量的借用时,变量被借用检查器标记为借用。在借用的 lifetime 期间,正如借用检查器所推断的那样,您不能改变或移动借用的变量,无论您是否将变量绑定声明为可变的。如果您创建了共享借用,则可以创建更多共享借用。但是,可变借用是排他性的——可变借用的变量在借用的生命周期内不能以任何其他方式使用。

这些规则确保在任何给定时间只有一个 "handle" 变量(绑定或可变借用)可用于改变变量。这是 Rust 确保的基本不变性。可变变量绑定的范围可以与借用的生命周期重叠这一事实不会改变这一点,因为您无法在借用的生命周期内通过绑定修改变量。

严格来说,没有"mutable variable"这样的东西;只有 可变变量绑定 。如果你拥有一个对象的所有权,你总是可以可变地绑定到它来修改它:

let s = "Hello".to_owned();
let mut s = s;
s.push_str(", world!");

您的代码还有一个微妙之处:println!() 是一个宏,而不是函数调用。它扩展为一些代码,仅 借用 您传递给 println!() 的参数。因此,虽然看起来您正在将 s 的所有权转让给 println!(),但实际上并没有。如果您改为使用获取所有权的宏,代码将停止编译:

let mut s = String::from("hello");
let r = &s;
dbg!(r, s);

导致错误

error[E0505]: cannot move out of `s` because it is borrowed
 --> src/main.rs:4:5
  |
3 |     let r = &s;
  |             -- borrow of `s` occurs here
4 |     dbg!(r, s);
  |     ^^^^^^^^^^^
  |     |
  |     move out of `s` occurs here
  |     borrow later used here
  |
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

另请参阅: