Rust 可以推断出所有控制流路径的寿命吗?

Can rust reason about lifetimes on all control flow paths?

考虑以下示例:

impl Foo {
    fn measure<'a>(&'a self) -> Vec<&'a Bar> {...}

    fn try_action<'a>(&'a mut self) -> Result<(), Vec<&'a Bar>> {
        let measurement = self.measure(); // this creates references that we may wish to return from this scope
        if measurement.is_empty() {
            drop(measurement); // just to be explicit and prove this is sound
            self.baz = 0;
            Ok(())
        } else {
            Err(measurement) // here we don't mutate self, instead we want to return a reason why we couldn't
        }
    }
}

自 rust 1.57.0 起,借用检查器将不接受此程序。令人沮丧的是,由于存在不可变借用(通过调用 measure 创建的借用),我无法将 *self 借用为可变借用。

我对此的理解是,它认为存在问题,因为 measurement 中包含的引用在技术上 可以 持续到函数范围结束(else块大小写)。然而,作为人类,我们可以看到这应该是合理的,因为在任何突变发生之前,所有不可变的借用都被丢弃了。我们不会将它们放在所有控制流路径上,但它们所在的路径上没有任何突变。因此,对于所有控制流路径,我们要么放弃不可变的借用(尽管这里不使用就足够了),要么我们从不改变结构。

为什么生锈不能解释这个? 这是 rustc 逻辑中的错误吗? 这是生命周期设计的限制吗? 这不正常吗?

你的理解没有错。这是当前借用检查器实现的一个限制,特别记录为非词法生命周期 RFC 的 problem #3。本质上,由于 measurement 是返回的引用,因此生命周期必须存在到函数结束之前,它将包含整个 if 语句而不考虑 drop.

作品有所改进(下一代借用检查器 polonius),但可能还需要一段时间才能稳定下来。