从单链列表中删除节点的错误是“无法移出借用的内容". [英] Deleting a node from singly linked list has the error "cannot move out of borrowed content"

查看:53
本文介绍了从单链列表中删除节点的错误是“无法移出借用的内容".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个单链接列表.删除节点时,前一个节点的 next 应该成为当前节点的 next ( prev-> next = curr-> next; ),如果索引匹配,则返回 data .否则,前一个节点将成为当前节点,而当前节点将成为下一个节点( prev = curr; curr = curr-> next; ):

I am making a singly-linked list. When you delete a node, the previous node's next should become the current node's next (prev->next = curr->next;) and return data if the index matches. Otherwise, the previous node becomes the current node and the current node becomes the next node (prev = curr; curr = curr->next;):

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

游乐场链接有关更多信息.

我该怎么做?我的方法不对吗?

How can I do this? Is my approach wrong?

推荐答案

在开始之前,请先阅读使用过多的链表学习 Rust.人们认为链表很简单,因为他们所学的语言要么不在乎是否引入了内存不安全性,要么完全从程序员手中夺走了这种代理权.

Before you start, go read Learning Rust With Entirely Too Many Linked Lists. People think that linked lists are easy because they've been taught them in languages that either don't care if you introduce memory unsafety or completely take away that agency from the programmer.

Rust都不做,这意味着您必须考虑以前可能从未想到的事情.

Rust does neither, which means that you have to think about things you might never have thought of before.

您的代码存在许多问题.您所问的无法移出借用的内容"这个问题已经被许多其他问题很好地涵盖了,因此没有理由重申所有这些好的答案:

There are a number of issues with your code. The one that you ask about, "cannot move out of borrowed content" is already well-covered by numerous other questions, so there's no reason to restate all those good answers:

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

TL;DR: You are attempting to move ownership of next from out of a reference; you cannot.

p.next = c.next;

您正在尝试修改不可变的引用:

You are attempting to modify an immutable reference:

let mut head = &self.head;

您允许人们删除过去的结尾,这对我来说没有意义:

You allow for people to remove one past the end, which doesn't make sense to me:

if index >= self.len()

在遍历整个树一次,但两次遍历,然后再次遍历以执行删除操作:

You iterate the entire tree not once, but twice before iterating it again to perform the removal:

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


与您的算法在Rust眼中存在缺陷(因为您尝试引入可变别名)相比,所有这些都相形见pale.如果您的代码能够编译,则可以对 previous 进行可变引用,而对 current 进行可变引用.但是,您可以从 previous 获取对 current 的可变引用.这将使您违反Rust的内存安全保证!


All of that pales in comparison to the fact that your algorithm is flawed in the eyes of Rust because you attempt to introduce mutable aliasing. If your code were able to compile, you'd have a mutable reference to previous as well as a mutable reference to current. However, you can get a mutable reference to current from previous. This would allow you to break Rust's memory safety guarantees!

相反,您只能跟踪 current ,并且当找到正确的索引时,请将其拆开并移动:

Instead, you can only keep track of current and, when the right index is found, break it apart and move the pieces:

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,
    }
}

另请参阅:

游乐场链接有关更多信息.

您的其余代码有很多问题,例如您的 insert 方法的结果不同于我以前见过的任何事实.

There are numerous problems with the rest of your code, such as the fact that the result of your insert method is unlike any I've ever seen before.

我怎么写.

这篇关于从单链列表中删除节点的错误是“无法移出借用的内容".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆