I know there are other structures which are better than the linked list, but I want to implement a singly linked list which has a remove function for study.
After struggling for a few hours, I wrote this code.
use std::rc::Rc;
use std::cell::RefCell;
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> Node<T> {
fn new(elem: T) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Node {
elem: elem,
next: None,
}))
}
}
pub struct List<T> {
head: Link<T>,
}
impl<T: Eq> List<T> {
pub fn new() -> Self {
List { head: None }
}
pub fn push(&mut self, elem: T) {
let new_head = Node::new(elem);
match self.head.take() {
Some(old_head) => {
new_head.borrow_mut().next = Some(old_head);
self.head = Some(new_head);
}
None => {
self.head = Some(new_head);
}
}
}
pub fn remove(&mut self, elem: T) {
let mut head = self.head.clone().unwrap();
if head.borrow().elem == elem {
self.head = head.borrow().next.clone();
return;
}
loop {
let next = head.borrow().next.clone();
match next {
None => return,
Some(ref node) => {
if node.borrow().elem == elem {
head.borrow_mut().next = node.borrow().next.clone();
}
head = node.clone();
}
}
}
}
}
fn main() {
let mut list = List::new();
list.push(3);
list.push(2);
list.push(1);
list.remove(2);
let head = list.head.unwrap().clone();
assert_eq!(head.borrow().elem, 1);
let next = head.borrow().next.clone().unwrap();
assert_eq!(next.borrow().elem, 3);
}
To iterate this list, I implemented a iterator.
pub struct Iter<T> {
next: Link<T>
}
impl<T> Iterator for Iter<T> {
type Item = Rc<RefCell<Node<T>>>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.next.clone();
let next_next = next.clone();
self.next = match next_next {
Some(node) => {
node.borrow().next.clone()
}
None => {
None
}
};
next
}
}
impl<T: Eq> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter { next: self.head.clone() }
}
}
fn main() {
let mut list = List::new();
list.push(3);
list.push(2);
list.push(1);
list.remove(2);
let mut it = list.iter();
let next_node = it.next().unwrap();
assert_eq!(next_node.borrow().elem, 1);
let next_node = it.next().unwrap();
assert_eq!(next_node.borrow().elem, 3);
let next_node = it.next();
assert_eq!(next_node.is_none(), true);
}
I'm not sure this code is good, because I think
- there are too many
clone()orborrow()calls. - code is long and not simple. (is using
RcandRefCellgood?)
Are there easier or simpler ways?
Even if this code is not so bad, are there weak or dangerous points?