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

标签 variables rust reference immutability borrow-checker

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

这编译:

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

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

最佳答案

让我们先稍微纠正一下术语。

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

借款有生命周期。这些生命周期将由借用检查器推断,并且它们与代码的词​​法结构(“非词法生命周期”)无关,尽管它们已经过去了。生命周期大致从创建借用点到最后使用它的点延伸。

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

这些规则确保只有一个变量的“句柄”——绑定(bind)或可变借用——可以在任何给定时间用于改变变量。这是 Rust 确保的基本不变性。可变变量绑定(bind)的范围可以与借用的生命周期重叠这一事实并没有改变这一点,因为您不能在借用的生命周期内通过其绑定(bind)来修改变量。

严格来说,不存在“可变变量”这回事;只有可变变量绑定(bind)。如果你拥有一个对象的所有权,你总是可以可变地绑定(bind)到它来修改它:

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)

也可以看看:
  • Does println! borrow or own the variable?
  • 关于variables - 为什么我可以使用可变变量,使其生命周期与不可变引用重叠,但我不能以相同的方式使用可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60611296/

    相关文章:

    c# - 无法添加对 dll 的引用。该组件是自动引用的 C#

    c++ - 为什么我的 std::ref 不能按预期工作?

    python - 使用 "try"查看是否定义了一个变量在 Python 中被认为是不好的做法?

    linux - 远程命令执行在这里文档和分配变量

    rust - 如何重新使用已将值移出的盒子?

    rust - 如何模式匹配 Option<&Path>?

    arrays - 可以在不先声明变量的情况下进行引用吗?

    java - 用不同的方法求循环的平均值?

    linux - bash 中的变量比较

    rust - 如何从字符串生成元组?