I've been trying to teach myself some Rust lately and wanted to practice a bit by implementing a simple linked list. I took some inspiration from the Rust library's linked list and tried to replicate the parts I already understood. Also I decided to make it singly-linked for now.
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
fn new(element: T) -> Self {
Node {
element: element,
next: None,
}
}
fn append(&mut self, element: Box<Node<T>>) {
self.next = Some(element);
}
}
pub struct LinkedList<T> {
head: Option<Box<Node<T>>>,
tail: Option<Box<Node<T>>>,
len: u32,
}
impl<T> LinkedList<T> {
pub fn new() -> Self {
head: None,
tail: None,
len: 0,
}
pub fn push(&mut self, element: T) {
let node: Box<Node<T>> = Box::new(Node::new(element));
match self.tail {
None => self.head = Some(node),
Some(mut ref tail) => tail.append(node),
}
self.tail = Some(node);
self.len += 1;
}
pub fn pop(&mut self) -> Option<T> {
//not implemented
}
pub fn get(&self, index: u32) -> Option<T> {
//not implemented
}
}
This is what I've got so far; from what I understand, the problem with this code is that the Box can not have more than one reference to it in order to preserve memory safety.
So when I set the list head to node in
None => self.head = Some(node),
I can't then go ahead and set
self.tail = Some(node);
later, am I correct so far in my understanding? What would be the correct way to do this? Do I have to use Shared like in the library or is there a way in which the Box or some other type can be utilized?
Your issue is that you are attempting to use a value (node) after having moved it; since Box<Node<T>> does not implement Copy, when you use it in the match expression:
match self.tail {
None => self.head = Some(node),
Some(ref mut tail) => tail.append(node),
}
node is moved either to self.head or to self.tail and can no longer be used later. Other than reading the obligatory Learning Rust With Entirely Too Many Linked Lists to see the different ways in which you can implement linked lists in Rust, I suggest that you first do some more research in the field of Rust's basic concepts, especially:
Ownership
References and Borrowing
What are move semantics?
You can go with something simpler than that, only using your nodes
use std::fmt;
struct Payload {
id: i32,
value: i32,
}
impl fmt::Display for Payload {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.id, self.value)
}
}
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> where T: std::fmt::Display{
fn new(element: T) -> Self {
Node {
element: element,
next: None,
}
}
fn append(&mut self, element: T) {
match &mut self.next {
None => {let n = Node {
element: element,
next: None,
};
self.next = Some(Box::new(n));
},
Some(ref mut x) => x.append(element),
}
}
fn list(& self) {
println!("{}", self.element);
match &self.next {
None => {},
Some(x) => x.list(),
}
}
}
fn main(){
let mut h = Node::new(Payload {id:1, value:1});
h.append(Payload {id:2, value:2});
h.append(Payload {id:3, value:3});
h.append(Payload {id:4, value:4});
h.append(Payload {id:5, value:5});
h.list();
h.append(Payload {id:6, value:6});
h.list();
}
Related
I get in trouble when trying to write a linked list in rust.
use std::rc::Rc;
#[derive(Debug)]
struct LinkedList<T> {
head: Link<T>,
tail: Link<T>,
}
type Link<T> = Option<Rc<Node<T>>>;
#[derive(Debug)]
struct Node<T> {
elem : T,
next : Link<T>
}
impl <T> LinkedList<T> {
fn new() -> Self {
LinkedList {
head : None,
tail : None
}
}
fn push_front(&mut self, elem: T) {
/* if head is None, take will return None */
let mut a : Option<i32> = None;
assert_eq!(a.take(), None);
let node = Rc::new(Node {
elem,
next : self.head.take(),
});
if self.tail.is_none() {
self.tail = Some(Rc::clone(&node));
}
self.head = Some(node);
}
fn pop_front(&mut self) -> Option<T> {
if self.head.is_none() {
return None;
}
if self.tail.as_ref().unwrap() == self.head.as_ref().unwrap() {}
todo!()
}
}
fn main() {
}
above code is a simple linked list demo.
the important code is the following, and it's buggy apparently:
if self.tail.as_ref().unwrap() == self.head.as_ref().unwrap() {}
I don't know how to judge head and tail whether point to the same object.
There is std::rc::Rc::ptr_eq() for exactly this kind of situation.
Returns true if the two Rcs point to the same allocation in a vein
similar to ptr::eq.
This question already has answers here:
How to handle "temporary value dropped" error when adapting Box-based tree structure to Rc+RefCell?
(2 answers)
Closed last month.
I was following this other post: Understanding Rust `Rc<RefCell<_>>` where op tried implementing a tree with Box and was successful in doing it but then tried implementing it with Rc and RefCell and found issues. The accepted answer compiles but doesn't work because it doesn't add nodes to the root. I tried updating the accepted answer a bit to try and get it to work but wasn't able to. Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference. But then if a borrow_mut() I get that value is a private field, so I'm assuming I can't access any properties of the contained value if it is a mutable reference?
What should I do to get this code to work?
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt;
#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
root: Option<Box<NodeBox<T>>>,
}
#[derive(Debug, Clone)]
struct NodeBox<T> {
value: T,
left: Option<Box<NodeBox<T>>>,
right: Option<Box<NodeBox<T>>>,
}
impl<T: Ord> TreeBox<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Option::Some(current_node) = node {
match current_node.value.cmp(&value) {
Ordering::Less => node = &mut current_node.right,
Ordering::Equal => return false,
Ordering::Greater => node = &mut current_node.left,
}
}
*node = Option::Some(Box::new(NodeBox {
value,
left: Option::None,
right: Option::None,
}));
return true;
}
}
#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
root: Option<Rc<RefCell<Node<T>>>>,
}
#[derive(Debug, Clone, PartialEq)]
struct Node<T> {
value: T,
left: Option<Rc<RefCell<Node<T>>>>,
right: Option<Rc<RefCell<Node<T>>>>,
}
impl<T: Ord + fmt::Debug> Tree<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Some(current_node) = node {
let current_node = current_node.borrow();
let cmp = current_node.value.cmp(&value);
let new_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
node = new_node;
}
// let mut node = &mut node;
*node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
true
}
}
fn main() {
let mut tree_box = TreeBox::new();
tree_box.insert(1);
tree_box.insert(2);
tree_box.insert(3);
let mut tree = Tree::new();
tree.insert(1);
tree.insert(2);
tree.insert(3);
println!("TreeBox: {:?}", tree_box);
println!("Tree: {:?}", tree);
}
The accepted answer compiles but doesn't work because it doesn't add nodes to the root.
You are right, and fixing the original solution, here a version that add the root node correctly:
pub fn insert(&mut self, value: T) -> bool {
//if no root, just create one
let mut node = if let Some(root) = &self.root {
Rc::clone(root)
} else {
self.root = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
return true;
};
loop {
let current_node = Rc::clone(&node);
let mut current_node = RefCell::borrow_mut(¤t_node);
let cmp = current_node.value.cmp(&value);
let next_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
if let Some(next_node) = next_node {
node = Rc::clone(next_node);
} else {
*next_node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
return true;
}
}
}
Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference.
The problem is slightly different. what happens is that you can't walk this Rc<RefCell> tree, at least not interactively like this, because the "borrow" of such structures need to be keep while you are working with it. And your implementation releases the "borrow" after each loop.
But then if a borrow_mut() I get that value is a private field, so I'm
assuming I can't access any properties of the contained value if it is
a mutable reference?
Not really, what is happening here is that you are not calling the function RefCell::borrow_mut that returns a RefMut<Node>, you are in fact calling <Rc as BorrowMut>::borrow_mut that returns &mut RefMut<...>. And by accessing the value you are trying the access the private field value from RefCell, not Node.
Notice that in my implementation I explicitly called RefCell::borrow_mut, that fixes this issue.
I have a BSTNode struct with an insert function in it:
pub struct BSTNode {
pub value: i32,
pub left: Option<Box<BSTNode>>,
pub right: Option<Box<BSTNode>>,
}
impl BSTNode {
pub fn insert(&mut self, val: i32) {
if val <= self.value {
match self.left {
None => {
self.left = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
} else {
match self.right {
None => {
self.right = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
}
}
}
I also have a BST struct to store that Node
struct BST {
node: Option<BSTNode>,
}
Is it possible to call the insert func implemented on the BSTNode through the BST struct?
What I mean is, that in the main.rs I could do this:
let mut root = BST::BST::new();
root.insert(5) // getting error obviously because method does not exist on BST struct.
Is it possible to kind of point to that BSTNode method what I call 'insert' through the BST struct?
I tried to just implement this method in the BST struct instead of keeping it in the BSTNode struct, but I am encountering a lot of problems, although that will be my last resort.
Keep it simple stupid solution: Just make an explicit delegator.
impl BST {
pub fn insert(&mut self, val: i32) {
if let Some(node) = self.node.as_mut() {
node.insert(val);
}
}
}
No need to reimplement anything, and the extra function call will almost certainly get inlined out unless you go out of your way to impede optimizations.
I have tried the examples in Learn Rust with Entirely Too Many LInked Lists, but I would like to make a linked list structure without a dedicated struct to point to the head of the list.
In the pop() function, since I only have a mutable reference to the node, so I "cannot move out of borrowed content". Is there a way to take out the node with only mutable reference or ownership is the requirement?
I have tried to use mem::replace(), but it's not for removing elements. Also the replacement on initializing a new node is pretty weird. Is there a more elegant way of writing a linked list without head pointer?
use std::mem;
type Link<T> = Option<Box<Node<T>>>;
pub struct Node<T> {
val: T,
next: Link<T>,
}
impl<T:Copy> Node<T> {
fn new(val: T) -> Self {
Node {
val: val,
next: None,
}
}
fn push(&mut self, val: T) {
let mut new_node = Node {
val: val,
next: Some(Box::new(mem::replace(self, Node::new(val)))),
};
self = &mut new_node;
}
pub fn pop(mut self) -> Option<T> {
let val = self.val;
self = *self.next.unwrap();
Some(val)
}
}
Here is my code:
struct Node<T> {
data: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
fn new(data : T) -> Node<T> {
Node { data: data, next: None }
}
fn new_with_next(data: T, next: Option<Box<Node<T>>>) -> Node<T> {
Node { data: data, next: next }
}
}
struct LinkedList<T> {
head: Box<Node<T>>,
size: u8,
}
impl<T> LinkedList<T> {
fn new(data: T) -> LinkedList<T> {
let new_node = Node::new(data);
let head = Box::new(new_node);
LinkedList { head: head, size: 1 }
}
fn insert(&mut self, data: T) {
let mut next = Some(self.head); // <-- error here
let new_node = Node::new_with_next(data, next);
self.head = Box::new(new_node);
self.size += 1;
}
}
I get this error:
src\linked_list.rs:28:29: 28:33 error: cannot move out of borrowed content [E0507]
src\linked_list.rs:28 let next = Some(self.head);
^~~~
I don't understand the error, nor how to fix it. I tried giving a reference to self.head to Some, however I'm changing the data type this inside Some this way.
The problem is that you take self by reference, therefore you cannot move out its head (it would become invalid), which let mut next = Some(self.head); would do.
std::mem::replace is a nice function for this:
fn insert(&mut self, data: T) {
let mut next = std::mem::replace(&mut self.head, Box::new(Node::new(data)));
self.head.next = Some(next);
self.size += 1;
}
It allows you to replace the head with a new node and get the old one at the same time, which Rust is happy about because head stays valid all along now.