cannot move out of an `Rc` error while making a singly linked stack

Viewed 274

I am trying to write a Singly Linked List in Rust such that we can only append to it's 'end'.
eg:
if the linked list is 1->2->3->5; we may push(7) and the result would be
1->2->3->5->7.
This is the code:

use std::cell::{Ref, RefCell};
use std::rc::Rc;

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

#[derive(Debug)]
struct SinglyLinkedList {
    head: Rc<Option<Node>>,
    len: usize,
}

impl Node {
    fn from(data: isize) -> Self {
        Self {
            data, next:Rc::from(None)
        }
    }
}

impl SinglyLinkedList {
    fn new() -> Self {
        Self {
            head: Rc::from(None),
            len: 0,
        }
    }

    fn append(&mut self, data: isize) {
        self.len += 1;
        let new_node = Node::from(data);
        if self.len == 0 {
            self.head = Rc::from(Some(new_node));
        }

        else {
            let mut curr_node = self.head.clone(); // Getting a mut reference to a Rc<Option<Node>>
            for _ in 0..self.len-1 {
                // Traversing the Linked List by going to the next node until we reach the end where we append the new_node
                curr_node = curr_node.unwrap().next.clone(); 
            }
            curr_node.unwrap().next = Rc::from(Some(new_node));
        }
    }
}

fn main() {
    let mut list = SinglyLinkedList::new();
    list.append(11);
    println!("{:?}", list);
}

When I execute it, I get the following error:

error[E0507]: cannot move out of an `Rc`
  --> src/main.rs:84:29
   |
84 |                 curr_node = curr_node.unwrap().next.clone();
   |                             ^^^^^^^^^^^^^^^^^^ move occurs because value has type `Option<Node>`, which does not implement the `Copy` trait
   |
help: consider borrowing the `Option`'s content
   |
84 |                 curr_node = curr_node.unwrap().as_ref().next.clone();
   |                                               +++++++++

According to my understanding, I used Rc<T> because I would have 2 owners during the append function: One the Node before the a Node (could be self.head) and the other would be curr_node which I use to traverse the Linked List. I also need mutability and tried using RefCell<T> but couldn't get it to work. I do not understand what to do to not get this error.

1 Answers
curr_node.unwrap().next = Rc::from(Some(new_node));

This line will never work, not even conceptually. Rc is non-mutable. The only way to mutate an Rc is if the current Rc is the only reference to the data, then you can use get_mut(). But as you run .clone() two lines earlier, it's clear that this is not the only reference to the data.

So there are multiple ways to achieve that:

  • In either solution, use Option<Rc<...>> instead of Rc<Option<...>>. You only need a reference if there is an item behind it, so having a reference to None is a waste of a reference and makes things a lot harder, due to the immutability problem.
  • Solution #1: use Option<Box<...>> instead of Option<Rc<...>>, as @cdhowie pointed out. You only ever have one reference to the next item, so having an Rc is overkill. And Box is mutable, so no interior mutability is needed.
  • Solution #2: If you want to keep the Rc, you need to add interior mutability, like Option<Rc<RefCell<...>>>.

I'll show both options.


Solution #1

I used Rc because I would have 2 owners during the append function:

The thought is not wrong, but we can use a reference to iterate through the items instead.

Also, minor fix: your self.len += 1 was at the wrong position.

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

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

impl Node {
    fn from(data: isize) -> Self {
        Self { data, next: None }
    }
}

impl SinglyLinkedList {
    fn new() -> Self {
        Self { head: None, len: 0 }
    }

    fn append(&mut self, data: isize) {
        let new_node = Node::from(data);
        if self.len == 0 {
            self.head = Some(Box::from(new_node));
        } else {
            let mut curr_node = &mut self.head;
            for _ in 0..self.len - 1 {
                // Traversing the Linked List by going to the next node until we reach the end where we append the new_node
                curr_node = &mut curr_node.as_mut().unwrap().next;
            }
            curr_node.as_mut().unwrap().next = Some(Box::from(new_node));
        }
        self.len += 1;
    }
}

fn main() {
    let mut list = SinglyLinkedList::new();
    list.append(1);
    list.append(2);
    list.append(3);
    list.append(5);
    println!("{:?}", list);
    list.append(7);
    println!("{:?}", list);
}
SinglyLinkedList { head: Some(Node { data: 1, next: Some(Node { data: 2, next: Some(Node { data: 3, next: Some(Node { data: 5, next: None }) }) }) }), len: 4 }
SinglyLinkedList { head: Some(Node { data: 1, next: Some(Node { data: 2, next: Some(Node { data: 3, next: Some(Node { data: 5, next: Some(Node { data: 7, next: None }) }) }) }) }), len: 5 }

Solution #2

This is a possible implementation with interior mutability:

use std::{cell::RefCell, rc::Rc};

#[derive(Debug)]
struct Node {
    data: isize,
    next: Option<Rc<RefCell<Node>>>,
}

#[derive(Debug)]
struct SinglyLinkedList {
    head: Option<Rc<RefCell<Node>>>,
    len: usize,
}

impl Node {
    fn from(data: isize) -> Self {
        Self { data, next: None }
    }
}

impl SinglyLinkedList {
    fn new() -> Self {
        Self { head: None, len: 0 }
    }

    fn append(&mut self, data: isize) {
        let new_node = Node::from(data);
        if self.len == 0 {
            self.head = Some(Rc::new(RefCell::new(new_node)));
        } else {
            let mut curr_node = self.head.as_ref().unwrap().clone();
            for _ in 0..self.len - 1 {
                // Traversing the Linked List by going to the next node until we reach the end where we append the new_node
                let next_node = curr_node.borrow().next.as_ref().unwrap().clone();
                curr_node = next_node;
            }
            curr_node.borrow_mut().next = Some(Rc::new(RefCell::new(new_node)));
        }
        self.len += 1;
    }
}

fn main() {
    let mut list = SinglyLinkedList::new();
    list.append(1);
    list.append(2);
    list.append(3);
    list.append(5);
    println!("{:?}", list);
    list.append(7);
    println!("{:?}", list);
}
SinglyLinkedList { head: Some(RefCell { value: Node { data: 1, next: Some(RefCell { value: Node { data: 2, next: Some(RefCell { value: Node { data: 3, next: Some(RefCell { value: Node { data: 5, next: None } }) } }) } }) } }), len: 4 }
SinglyLinkedList { head: Some(RefCell { value: Node { data: 1, next: Some(RefCell { value: Node { data: 2, next: Some(RefCell { value: Node { data: 3, next: Some(RefCell { value: Node { data: 5, next: Some(RefCell { value: Node { data: 7, next: None } }) } }) } }) } }) } }), len: 5 }
Related