非词法生命周期 (NLL) 完全稳定

2022 年 8 月 5 日 · Niko Matsakis 代表 NLL 工作组

从 Rust 1.63(下周发布)开始,“非词法生命周期”(NLL)工作将默认启用。NLL 是 Rust 借用检查器的第二次迭代。 RFC 实际上很好地突出了一些激励性的例子。“但是,”我听到你们说,“NLL 不是已经包含在 Rust 2018 中了吗?” 是的,没错!但那时,NLL 仅对 Rust 2018 代码启用,而 Rust 2015 代码在“迁移模式”下运行。在“迁移模式”下,编译器会运行旧的新的借用检查器并比较结果。这样,我们可以为那些原本就不应该编译的旧代码发出警告;我们还可以限制新代码中任何错误的影响。随着时间的推移,我们已经将迁移模式限制得越来越接近仅运行新式借用检查器:在下一个版本中,该过程完成,所有 Rust 代码都将使用 NLL 进行检查。

删除旧借用检查器对用户有何影响?

目前,我们几乎完全合并了“迁移模式”和“常规模式”,因此切换到 NLL 对用户体验的影响很小。许多诊断信息发生了变化,大多数情况下是变得更好了 -- Jack Huey 在他的博客文章中提供了完整详细信息

功劳归于应得的人

删除旧借用检查器的工作已经进行了多年。这是一个漫长、乏味且基本上吃力不讨好的过程。我们想花点时间来突出参与其中的各个成员,并确保他们因辛勤工作而获得认可。

如果您想了解更多细节,Jack 的博客文章包含所有涉及工作的详细叙述! 这是一篇有趣的读物。

展望未来:我们对“未来的借用检查器”有何期待?

Rust 借用检查的下一个前沿是将 polonius 项目从研究实验转变为生产代码。Polonius 是下一代借用检查器,它在 2018 年从主要的 NLL 工作中“分离”出来,当时我们正在准备在生产环境中发布 NLL。它最重要的贡献是修复了借用检查器的一个已知限制,以下示例证明了这一点

fn last_or_push<'a>(vec: &'a mut Vec<String>) -> &'a String {
    if let Some(s) = vec.last() { // borrows vec
        // returning s here forces vec to be borrowed
        // for the rest of the function, even though it
        // shouldn't have to be
        return s; 
    }
    
    // Because vec is borrowed, this call to vec.push gives
    // an error!
    vec.push("".to_string()); // ERROR
    vec.last().unwrap()
}

这个例子今天无法编译(自己尝试一下),尽管没有充分的理由这样做。您通常可以通过编辑代码以引入冗余的 let 来解决问题(如本例所示),但使用 polonius,它将按原样编译。如果您想了解更多关于 polonius(和现有的借用检查器)如何工作的信息1,您可以 观看我在 Rust Belt Rust 上的演讲

  1. 或者 polonius 这个名字的由来!