生存期和闭包捕获的变量如何交互?[复制]

How do lifetimes and variables captured by closures interact? [duplicate]

提问人:Kami SM 提问时间:5/29/2023 最后编辑:cafce25Kami SM 更新时间:5/29/2023 访问量:57

问:

我目前正在从《The Rust Programming Language》一书中学习 Rust,似乎我遇到了以下情况:

fn main() {
    let mut s = String::from("Hello");
    let mut add_suffix = || s.push_str(" world");
    println!("{s}");
    add_suffix();
}

导致编译器错误:

error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
 --> src/main.rs:4:16
  |
3 |     let mut add_suffix = || s.push_str(" world");
  |                          -- - first borrow occurs due to use of `s` in closure
  |                          |
  |                          mutable borrow occurs here
4 |     println!("{s}");
  |                ^ immutable borrow occurs here
5 |     add_suffix();
  |     ---------- mutable borrow later used here
  |
  = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

我所理解的是,以某种方式对(我知道这需要可变引用)进行可变引用,从而增加了从闭包定义开始并在调用结束时结束的生存期。add_suffixspush_stradd_suffix

但我似乎不明白为什么在我们调用关闭之前会发生这种情况(即),为什么 Rust 会强制执行它,这有什么不安全的?如果我们想象该可变引用的生命周期在调用时开始和结束,我看不出出错的方式。add_suffix

rust compiler-errors 闭包 生存期

评论


答:

-1赞 cyqsimon 5/29/2023 #1

这与寿命无关。正如您在编译器错误中看到的那样,根本没有提到生存期。相反,这是一个“不能同时变异别名”的简单情况。具体原因我就不多说了;TLDR 是“数据竞赛”。如果您对“为什么”感兴趣,这里有一些有用的读物:Rust 书可变混叠问题

在您的示例中,当闭包被定义并存储在变量中时,它已经通过可变引用捕获了。这意味着在可变引用被释放之前(也就是直到超出范围,在代码片段的第 5 行之后),不能存在其他引用(因为可变引用是排他性的)。因此,您不能在第 4 行借款。ssadd_suffixs

评论

0赞 Kami SM 5/30/2023
很感激,我已经进入了 Rust 的书,但我似乎不明白为什么定义闭包首先会捕获变量。
0赞 Mark Saving 6/10/2023
这与数据争用无关,数据争用只能在并发代码中发生。Rust 有引用别名规则的原因还有很多。