Search code examples
rustlinked-listsingly-linked-list

writing pop from end function in rust


This is my singly linked list code have to implement pop from end and pop from front functions still, but I'm having difficulty in writing pop from end function

#![allow(warnings)]

#[derive(Clone)]
struct List {
    el: i32,
    next: Box<Option<List>>
}

impl List {
    fn new(val: i32) -> List {
        return List {
            el: val,
            next: Box::new(None)
        }
    }

    fn from(arr: &[i32]) -> List {
        let mut head = List::new(arr[0]);

        let mut current = &mut head;
        for &val in &arr[1..] {
            /* current.next = Box::new(Some(List::new(val)));
            current = (*current.next).as_mut().unwrap(); */
            current.append(val);
        }
        return head
    }

    fn append(&mut self, val: i32) {
        let mut current = self;
        while let Some(ref mut next_node) = *current.next {
            current = next_node;
        }
        current.next = Box::new(Some(List::new(val)));
    }

    fn prepend(&mut self, val:i32) {
        // std::mem::replace(dest, src): 
        //    Moves src into the referenced dest, returning the previous dest value
        let old_self = std::mem::replace(self, List::new(val));
        self.next = Box::new(Some(old_self));
    }
}

fn main() {
    let mut list = List::new(42);
    list.append(32);
    list.append(2321);
    list.append(2839);
    list.prepend(69);
    list.pop(); // 2839 // difficulty in implementing this
    println!("{}", list);

    let mut list = List::from(&[1, 2, 3]);
    list.prepend(0);
    println!("{}", list);
}

Should I use Rc and RefCell to implement a singly linked list? I'm a beginner, so please help. Thanks!


Solution

  • Possible solution

        fn pop(&mut self) -> Option<List> {
            match &mut*self.next {
                // if self.next is None
                // that means that the list only have one element
                // and idk what's you desired behavior, but I just return None
                None => None,
    
                // we check the next element
                Some(n) => {
                    if n.next.is_none() {
                        // if the next element is the terminal element
                        // we take the self.next
                        // that will change the current.next to None
                        self.next.take()
                    }else{
                        // if the next element is not the terminal element
                        n.pop()
                    }
                }
            }
        }
    
    fn main() {
        let mut list = List::new(42);
        list.append(32);
        list.append(2321);
        list.append(2839);
        list.prepend(69);
        println!("{}", list);
    
        println!("{:?}", list.pop());
        println!("{}", list);
    
        let mut list = List::from(&[1, 2, 3]);
        list.prepend(0);
        println!("{}", list);
    
        println!("{:?}",list.pop());
        println!("{}", list);
    }
    
    Output
    LinkedList([69, 42, 32, 2321, 2839])
    
    Some(List { el: 2839, next: None })
    LinkedList([69, 42, 32, 2321])
    
    LinkedList([0, 1, 2, 3])
    
    Some(List { el: 3, next: None })
    LinkedList([0, 1, 2])
    
    Remark
    ref deref box

    there is this pattern &*self.next

    let x: Box<Option<List>> =     self.next; // illegal, you cannot move it out
    let x: Option<List>      =   * self.next; // illegal, you cannot move it out
    let x: &Option<List>     = & * self.next; // legal, you can borrow the value
    
    derive debug

    you can use #[derive(Debug)] to make debug easier, and don't need to implement Display all the time.

    #[derive(Clone, Debug)]
    struct List {
        el: i32,
        next: Box<Option<List>>
    }