019 peek is realized through the double linked list of rust

Time:2021-7-30

introduce

Video address:www.bilibili.com/video/av78062009/
Relevant source code:github.com/anonymousGiga/Rust-link…

Details

In this section, we implement peek of double linked list.

Implement peek

According to our previous experience in implementing single linked list, we can easily think of how to implement our peek function, as follows:

    pub fn peek_front(&self) -> Option<&T> {
        self.head.as_ref().map(|node| {
            &node.borrow().elem
        })
    }

Compile and report errors.

Solution: we can check the borrow function of refcell in the manual and find that the definition is as follows:

pub fn borrow(&self) -> Ref<'_, T>

pub fn borrow_mut(&self) -> RefMut<'_, T>

Let’s change the code as follows:

    pub fn peek_front(&self) -> Option<Ref<T>> {
        self.head.as_ref().map(|node| {
            node.borrow()
        })
    }

After compilation, if the error is still reported and ref is not found, add the following to the code:

use std::cell::Ref;

Continue to report errors as follows:

= note: expected enum `std::option::Option<std::cell::Ref<'_, T>>`
              found enum `std::option::Option<std::cell::Ref<'_, Node<T>>>`

The expectation is

std::option::Option<std::cell::Ref<'_, T>>

But what you get here is

std::option::Option<std::cell::Ref<'_, Node<T>>>

It’s easy to see that we need to

Node<T>

Take out the T in the.

How to solve this problem?

Here we use it

std::cell::ref 

The map in is as follows:

pub fn map<U, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
where
    F: FnOnce(&T) -> &U,
    U: ?Sized, 

Finally, our peek code is as follows:

    pub fn peek_front(&self) -> Option<Ref<T>> {
        self.head.as_ref().map(|node| {
            Ref::map(node.borrow(), |node| &node.elem)
        })
    }

Test code

#[test]
fn peek() {
    let mut list = List::new();
    assert!(list.peek_front().is_none());
    list.push_front(1); list.push_front(2); list.push_front(3);

    assert_eq!(&*list.peek_front().unwrap(), &3);
}

Complete code

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

pub struct List<T> {
    head: Link<T>,
    tail: Link<T>,
}

type Link<T> = Option<Rc<RefCell<Node<T>>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
    prev: Link<T>,
}

impl<T> Node<T> {
    fn new(elem: T) -> Rc<RefCell<Self>> {
        Rc::new(RefCell::new(Node {
            elem: elem,
            prev: None,
            next: None,
        }))
    }
}

impl<T> List<T> {
    pub fn new() -> Self {
        List { head: None, tail: None }
    }

    pub fn push_front(&mut self, elem: T) {
        let node = Node::new(elem);
        match self.head.take() {
            Some(head) => {
                //Take the variable reference and use the arrow_ mut
                head.borrow_mut().prev = Some(node.clone());
                node.borrow_mut().next = Some(head);
                self.head = Some(node);
            }
            None => {
                self.tail = Some(node.clone());
                self.head = Some(node);
            }
        }
    }

    pub fn pop_front(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            match node.borrow_mut().next.take() {
                Some(next) => {
                    next.borrow_mut().prev.take();
                    self.head = Some(next);
                }
                None => {
                    self.tail.take();
                }
            }
            //Value using into_ inner
            Rc::try_unwrap(node).ok().unwrap().into_inner().elem
        })
    }

    //pub fn peek_front(&self) -> Option<&T> {
    pub fn peek_front(&self) -> Option<Ref<T>> {
        self.head.as_ref().map(|node| {
            //node.borrow()
            Ref::map(node.borrow(), |node| &node.elem)
        })
    }
}

#[cfg(test)]
mod tests {
    use super::List;

    #[test]
    fn basics() {
        let mut list = List::new();

        assert_eq!(list.pop_front(), None);

        list.push_front(1);
        list.push_front(2);
        list.push_front(3);

        assert_eq!(list.pop_front(), Some(3));
        assert_eq!(list.pop_front(), Some(2));

        list.push_front(4);
        list.push_front(5);

        assert_eq!(list.pop_front(), Some(5));
        assert_eq!(list.pop_front(), Some(4));

        assert_eq!(list.pop_front(), Some(1));
        assert_eq!(list.pop_front(), None);
    }
}

This work adoptsCC agreement, reprint must indicate the author and the link to this article

Linghu rushed