在`while let Some() = xxx`循环之后,为什么`tail`仍然被借用?

4

我一直在解决一些 LeetCode 的问题,其中遇到了一个我无法解释的问题。

这里是完整的源代码:

#[derive(Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

impl ListNode {
    fn new(val: i32) -> Self {
        ListNode { next: None, val }
    }
}

fn main() {
    let mut list = Some(Box::new(ListNode {
        val: 1,
        next: Some(Box::new(ListNode {
            val: 2,
            next: Some(Box::new(ListNode { val: 3, next: None })),
        })),
    }));

    let mut tail = &mut list.as_mut().unwrap().next;

    // This compiles fine
    // while tail.is_some() {
    //     tail = &mut tail.as_mut().unwrap().next;
    // }

    // This compiles fine
    // while let Some(ref mut node) = tail {
    //     tail = &mut node.next;
    // }

    // However this does not
    while let Some(node) = tail.as_mut() {
        tail = &mut node.next;
    }

    *tail = Some(Box::new(ListNode::new(4)));
    println!("{:#?}", list);
}

这是错误信息:

error[E0506]: cannot assign to `*tail` because it is borrowed
  --> src/main.rs:39:5
   |
35 |     while let Some(node) = tail.as_mut() {
   |                            ---- borrow of `*tail` occurs here
...
39 |     *tail = Some(Box::new(ListNode::new(4)));
   |     ^^^^^
   |     |
   |     assignment to borrowed `*tail` occurs here
   |     borrow later used here


为什么在 while let Some() = xxx 循环之后,tail 仍然被借用?
1个回答

5
这是由于while let ...被匹配项tail.as_mut()while let中的交互引起的,该表达式在位置表达式上下文中是一个值表达式。
简单地说,为了使while let循环的主体能够访问绑定(node),编译器需要借用tail(在循环之前创建),调用Option上的as_mut(),保持对该Option的隐式临时借用存活,并将as_mut()返回的值绑定到node。就编译器而言,node的生命周期取决于那个Option,因为它通过&'a mut tail -> as_mut(&'a mut self) -> &'a mut ListNode传递。
当您重新分配tail=&mut node.next时,这仍然是隐式生命周期'a的值,在循环创建的原始临时变量上借用。
然后在循环后将*tail赋值时,会发生冲突:原始的Option上有一个隐式借用,用于调用as_mut()首先创建node,然后创建tail,但现在您正在向-只要编译器可以看到-该选项进行赋值。但是,您不能在该选项被借用时使其无效,因此会出现错误。
这就是为什么编译器在while let-循环的检查位置指向borrow of *tail occurs here(请注意解引用),然后令人困惑地指向*tail=Some(...)是使用该借用的点。
另外两个示例没有在检查者中创建临时变量以对Option进行方法调用,因此编译良好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接