qmzp
qmzp

Reputation: 79

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!

Upvotes: -1

Views: 53

Answers (1)

啊鹿Dizzyi
啊鹿Dizzyi

Reputation: 1050

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

Upvotes: 1

Related Questions