Rust LinkedList 中的借用检查器错误的原因是什么?

问题描述 投票:0回答:1

我正在编写一个 fn 来从 LinkedList 中的最后一个 pos 中弹出元素,但是在这种情况下会发生双 mut ref 错误,我试图获取倒数第二个节点,以便我可以砍掉尾部

fn pop(&mut self) -> Option<T> {
        match self.head {
            None => None,
            Some(ref mut head) => {
                let mut curr = head;

                while let Some(ref mut next) = curr.next {
                    if next.next.is_none() {
                        break;
                    }

                    curr = next;
                }

                let taken = curr.next.take();
                taken.map(|x| x.data)
            }
        }
    }

但是代码在没有检查的情况下编译

fn pop(&mut self) -> Option<T> {
        match self.head {
            None => None,
            Some(ref mut head) => {
                let mut curr = head;

                while let Some(ref mut next) = curr.next {
                    // if next.next.is_none() {
                    //     break;
                    // }

                    curr = next;
                }

                let taken = curr.next.take();
                taken.map(|x| x.data)
            }
        }
    }

错误

error[E0499]: cannot borrow `curr.next` as mutable more than once at a time
  --> src\main.rs:70:29
   |
62 |                 while let Some(ref mut next) = curr.next {
   |                                ------------ first mutable borrow occurs here
...
70 |                 let taken = curr.next.take();
   |                             ^^^^^^^^^^^^^^^^
   |                             |
   |                             second mutable borrow occurs here
   |                             first borrow later used here


似乎无法弄清楚这个问题,因为我是 Rust 新手。任何帮助将不胜感激。

完整代码

use std::fmt::Debug;

#[derive(Debug)]
struct Node<T> {
    data: T,
    next: Option<Box<Node<T>>>,
}

#[derive(Debug)]
struct LinkedList<T> {
    head: Option<Box<Node<T>>>,
    len: usize,
}


impl<T: Debug> LinkedList<T> {
    fn new() -> Self {
        Self { head: None, len: 0 }
    }

    fn push(&mut self, data: T) {
        match self.head {
            None => self.head = Some(Box::new(Node::new(data))),
            Some(ref mut head) => {
                let mut curr = head;

                while let Some(ref mut next) = curr.next {
                    curr = next;
                }

                curr.next = Some(Box::new(Node::new(data)));
            }
        }

        self.len += 1;
    }

    // head -> 1 -> 2

    fn pop(&mut self) -> Option<T> {
        match self.head {
            None => None,
            Some(ref mut head) => {
                let mut curr = head;

                while let Some(ref mut next) = curr.next {
                    // if next.next.is_none() {
                    //     break;
                    // }

                    curr = next;
                }

                let taken = curr.next.take();
                taken.map(|x| x.data)
            }
        }
    }
}

impl<T> Node<T> {
    fn new(data: T) -> Self {
        Node { data, next: None }
    }
}
rust borrow-checker
1个回答
3
投票

这是借用检查器的一个众所周知的缺陷。您的代码可以使用下一代 Polonius 借用检查器进行编译。

解决此问题的方法是不在循环中保留可变引用:

while curr.next.is_some() {
    curr = curr.next.as_mut().unwrap();
}

这既尴尬又丑陋,但这就是我们现在能做的。

© www.soinside.com 2019 - 2024. All rights reserved.