Search code examples
rustlinked-list

How to implement a remove function in a linked list in safe rust? (cannot assign to *node because is borrowed)


struct Node<T> {
  content: T,
  next: Option<Box<Node<T>>>
}

struct LinkedList<T> {
  first: Option<Box<Node<T>>>,
  size: i64
}

impl<T: std::default::Default + std::cmp::PartialEq> LinkedList<T> {
  fn new() -> Self {
    LinkedList { first: None, size: 0 }
  }

  fn push(&mut self, value: T) {
    let mut tmp_node = Box::new(Node { content: value, next: None });
    let old_first_node = std::mem::replace(&mut self.first, None);
    tmp_node.next = old_first_node;
    self.first = Some(tmp_node);

    self.size += 1;
  }

  fn pop(&mut self) -> Option<T> {
    let mut old_first = std::mem::replace(&mut self.first, None);
    match &mut old_first {
      None => {
        return None;
      },
      Some(ptr) => {
        self.first = std::mem::take(&mut ptr.next);
        let val_to_return = std::mem::take(&mut ptr.content);
        return Some(val_to_return);
      }
    }
  }

  fn remove(&mut self, value: T) {
    let mut current_node = &mut self.first;

    while let Some(node) = current_node {
      if node.content == value {
        *current_node = node.next.take();
        break;
      }
      current_node = &mut node.next;
    }
  }
}

fn main() {
  
}

I tried to implement this function a lot but every solution I thought of, the compiler complains about some "borrow" error, in this case, the error is "cannot assign to *current_node because is borrowed". How can i avoid this error and make the current node be the next node of the linked list?


Solution

  • Actually, your code is correct, it's a limitation of the compiler that it doesn't accept it. It is accepted with the nightly Polonius borrow checker.

    The simplest solution is to replace while let with is_some() and unwrap()s:

    fn remove(&mut self, value: T) {
        let mut current_node = &mut self.first;
    
        while current_node.is_some() {
            if current_node.as_mut().unwrap().content == value {
                *current_node = current_node.as_mut().unwrap().next.take();
                break;
            }
            current_node = &mut current_node.as_mut().unwrap().next;
        }
    }