如果让即使#返回后借撑![功能(NLL)] [复制](If let borrow stays aft

2019-09-28 09:07发布

这个问题已经在这里有一个答案:

  • 在循环双可变借错误甚至NLL发生在 1个回答

我工作在一个大的文件,但是这是导致同样的问题一个小玩具的例子。 很抱歉,如果该示例本身是没有意义的。

#![feature(nll)]
struct S(i32);

impl S {
    fn foo(&mut self) -> Option<&i32> {
        if let Some(val) = self.bar() {
            return Some(val);
        }
        let y = &mut self.0;
        None
    }

    fn bar(&mut self) -> Option<&i32> {
        None
    }
}

fn main() {
    S(0).foo();
}

这不通过借检查:

error[E0499]: cannot borrow `self.0` as mutable more than once at a time
 --> test.rs:9:17
  |
6 |         if let Some(val) = self.bar() {
  |                            ---- first mutable borrow occurs here
...
9 |         let y = &mut self.0;
  |                 ^^^^^^^^^^^ second mutable borrow occurs here
  |
note: first borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 5:5...
 --> test.rs:5:5
  |
5 | /     fn foo(&mut self) -> Option<&i32> {
6 | |         if let Some(val) = self.bar() {
7 | |             return Some(val);
8 | |         }
9 | |         let y = &mut self.0;
10| |         None
11| |     }
  | |_____^

如果不是这是有效的(即使没有#![feature(nll)] ),因为它是在返回if let块? 值得一提的是,如果我改变了if let块以下,它编译罚款

if self.bar().is_some() {
    return self.bar();                                                                                      
}

Answer 1:

让我们来看看在寿命在这里详细。 函数foo()被脱糖到

fn foo<'a>(&'a mut self) -> Option<&'a i32>

即返回的值最多只要住的self ; 类似地,对于bar()

foo()线

if let Some(val) = self.bar() {

创建的借self那住了一段终身'b返回的参考val也有这一辈子'b 。 既然你那么返回Some(val)寿命'b必须活得比寿命'a中的self参数foo()这比运行时绝对不再是foo() 这意味着你不能借self再次在以后的任何一点在foo()

我认为,在这个例子中令人惊讶的是,借self即使发生,如果bar()返回None 。 直观地说,我们觉得没有提及在这种情况下返回,所以我们并不需要借位。 然而,在防锈寿命由类型检查器检查,类型检查不明白的类型的不同值的含义。 返回的值bar()的类型为Option<&'b i32>不管它是否返回NoneSome ,和寿命'b HAST是只要至少与'a -给定的约束,没有其他解决方案,所以借检查有权拒绝此。

对于非词汇的寿命,编译器可以引入不绑定到词法范围,并且可以在以前不可能实现的方式重叠,更灵活的寿命。 但是,如果仅仅是没有使用寿命满足所有约束,NLLS不会帮你。

你给最后的代码片断是相当不同的。 让我们添加寿命:

if self.bar<'b>().is_some() {
    return self.bar<'c>();                                                                                      
}

现在我们调用bar()两倍,并且每个电话都可以有不同的寿命。 只有终身'c需要活得比'a现,但寿命'b仅需要足够长的时间来调用is_some()的结果。 与寿命借'c只发生在分支,并且不发生冲突。



文章来源: If let borrow stays after return even with #![feature(nll)] [duplicate]