当前位置: 首页 > 知识库问答 >
问题:

从单链表中删除节点时出现错误“无法移出借用的内容”

章高爽
2023-03-14

我正在制作一个单链表。删除节点时,上一个节点的next应成为当前节点的nextprev-

struct Node<T> {
    data: T,
    next: Option<Box<Node<T>>>,
}

struct LinkedList<T> {
    head: Option<Box<Node<T>>>,
}

impl LinkedList<i64> {
    fn remove(&mut self, index: usize) -> i64 {
        if self.len() == 0 {
            panic!("LinkedList is empty!");
        }
        if index >= self.len() {
            panic!("Index out of range: {}", index);
        }
        let mut count = 0;
        let mut head = &self.head;
        let mut prev: Option<Box<Node<i64>>> = None;
        loop {
            match head {
                None => {
                    panic!("LinkedList is empty!");
                }
                Some(c) => {
                    // I have borrowed here
                    if count == index {
                        match prev {
                            Some(ref p) => {
                                p.next = c.next;
                                //       ^ cannot move out of borrowed content
                            }
                            _ => continue,
                        }
                        return c.data;
                    } else {
                        count += 1;
                        head = &c.next;
                        prev = Some(*c);
                        //          ^^ cannot move out of borrowed content
                    }
                }
            }
        }
    }

    fn len(&self) -> usize {
        unimplemented!()
    }
}

fn main() {}
error[E0594]: cannot assign to field `p.next` of immutable binding
  --> src/main.rs:31:33
   |
30 |                             Some(ref p) => {
   |                                  ----- consider changing this to `ref mut p`
31 |                                 p.next = c.next;
   |                                 ^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:31:42
   |
31 |                                 p.next = c.next;
   |                                          ^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:40:37
   |
40 |                         prev = Some(*c);
   |                                     ^^ cannot move out of borrowed content

操场链接了解更多信息。

我该怎么做?我的方法错了吗?


共有1个答案

齐典
2023-03-14

在你开始学习之前,先去读一读链表太多的书。人们认为链表很容易,因为他们所学的语言要么不在乎是否会导致内存不安全,要么完全剥夺了程序员的代理权。

生锈两者都没有,这意味着你必须考虑一些你以前可能从未想过的事情。

您的代码有许多问题。你问的那个“不能搬出借来的内容”已经被许多其他问题很好地涵盖了,所以没有理由重申所有这些好答案:

  • 无法移出借用的内容
  • 尝试转移所有权时无法移出借用的内容
  • 错误[E0507]:无法移出借用的内容

TL;DR:您正试图将next的所有权从引用中移出;你不能。

p.next = c.next;

您正试图修改不可变引用:

let mut head = &self.head;

你允许人们在最后删除一个,这对我来说没有意义:

if index >= self.len()

您不是迭代整个树一次,而是两次,然后再次迭代以执行删除:

if self.len() == 0
if index >= self.len()

所有这一切与你的算法在锈迹斑斑的人眼中是有缺陷的这一事实相比都相形见绌,因为你试图引入可变的别名。如果您的代码能够编译,您将有一个对previous的可变引用以及对current的可变引用。但是,您可以从previous中获得对当前的可变引用。这将允许您打破Rust的内存安全保证!

相反,您只能跟踪当前,当找到正确的索引时,将其拆分并移动片段:

fn remove(&mut self, index: usize) -> T {
    self.remove_x(index)
        .unwrap_or_else(|| panic!("index {} out of range", index))
}

fn remove_x(&mut self, mut index: usize) -> Option<T> {
    let mut head = &mut self.head;

    while index > 0 {
        head = match { head }.as_mut() {
            Some(n) => &mut n.next,
            None => return None,
        };
        index -= 1;
    }

    match head.take().map(|x| *x) {
        Some(Node { data, next }) => {
            *head = next;
            Some(data)
        }
        None => None,
    }
}

另见:

  • 迭代递归结构时无法获得可变引用:不能一次多次借用可变引用
  • 如何从Box中获得自有价值?

操场链接了解更多信息。

您的其余代码存在许多问题,例如insert方法的结果与我以前见过的任何方法都不一样。

我会怎么写。

 类似资料:
  • 当我通过GPS移除一个节点时,当我试图打印二叉树时,会出现堆栈溢出。下面是我的一些代码。我不能理解它将如何工作良好,如果我删除的名称,但不是,如果我删除的坐标,因为我正在使用相同的删除方法。 我得到的确切错误是“Exe:0xC00000FD中0x013214D6处的未处理异常:堆栈溢出(参数:0x00000001,0x00152FFC)”。在按坐标删除后,在打印函数中会出现这种情况,但如果按名称删

  • 我在以递归方式从循环单链表中删除单个节点/值时遇到了一些问题(当然,如果可能的话)。我的代码只从中间删除,而不是从第一个或最后一个地方删除。 在以递归方式删除其中一个连接后,我不知道如何建立连接。我的意思是,如果我要删除第一个元素,那么我需要将最后一个节点连接到下一个节点。 这是我的代码: 参数和返回: 查找尾部功能:

  • 我的问题是,如果用户输入一个姓氏,并且在链接列表中有多个相同的姓氏,并且其中一个姓氏在head节点中。如何在不删除头部节点的情况下删除另一个姓氏。我尝试了一些我能想到的方法,但是删除了所需的节点(这很好),包括头部节点(这不是我想要的…)

  • 我试图从基于阉羊的双链表中删除一个元素,该列表中的节点满足返回bool的函数。由于某种原因,替换节点的前一个指针(下一个被删除)不更新,而是引用回它自己。 我的代码 测试结果

  • 我正在尝试从单链接列表中删除最后一个节点。但我仍然无法在代码中解决此错误。我的方法没有删除最后一个节点。调用delete方法后,它仍然显示我要删除的节点。列表的其余部分将被删除,但最后一个节点本身不会被删除。你能告诉我我遗漏了什么,或者错误在哪里吗? LinkedList: 列表: 节点:

  • 我试图在Rust中创建一个不相交的集合数据结构。相关代码为: 我得到的错误是: 我不确定我是否完全理解了借用检查器,但是我使用引用来避免对结构本身拥有所有权,这样它们就可以像在其他语言中一样被指向和重新分配。 我可以通过从结构中的引用中删除来避免这些错误,但是我不能更改每个集合的父集合,因为它们是不可变的。 我读过类似的问题,比如: Rust:“无法移出‘self’,因为它是借来的”错误 无法从中