A BorrowMutError report when use a different Argument

I wrote a Double-end linked list, "already borrowed: BorrowMutError" Error reported when call the delete method with "&head.borrow().next.as_ref().unwrap() " but works ok with argument "&head".

I spent hours unable to figure out why is that ? Please help. thank you.

struct Node<T> {
    value: T,
    next: Option<Rc<RefCell<Node<T>>>>,
    prev: Option<Rc<RefCell<Node<T>>>>,
}

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

fn delete<T>(node: &Rc<RefCell<Node<T>>>) {
    let prev_node = node.borrow().prev.clone();
    let next_node = node.borrow().next.clone();
    node.borrow_mut().prev = None;
    node.borrow_mut().next = None;
    if let Some(ref prev) = prev_node{
// Error: already borrowed: BorrowMutError report here when 
// call the delete method with argument: &head.borrow().next.as_ref().unwrap() 
// but works ok with argument: &head
        prev.borrow_mut().next = next_node.clone();  
    }
    
    if let Some(next) = next_node {
        next.borrow_mut().prev = prev_node;
    }
}

fn insert_after<T>(node: &Rc<RefCell<Node<T>>>, value: T) {
    let new_node = Rc::new(RefCell::new(Node::new(value)));
    let next_node = node.borrow().next.clone();
    
    node.borrow_mut().next = Some(new_node.clone());
    new_node.borrow_mut().prev = Some(node.clone());
    
    if let Some(next) = next_node {
        new_node.borrow_mut().next = Some(next.clone());
        next.borrow_mut().prev = Some(new_node);
    }
}

fn insert_before<T>(node: &Rc<RefCell<Node<T>>>, value: T) {
    let new_node = Rc::new(RefCell::new(Node::new(value)));
    let prev_node = node.borrow().prev.clone();
    
    node.borrow_mut().prev = Some(new_node.clone());
    new_node.borrow_mut().next = Some(node.clone());
    
    if let Some(prev) = prev_node {
        new_node.borrow_mut().prev = Some(prev.clone());
        prev.borrow_mut().next = Some(new_node);
    }
}

fn traverse_forward<T: std::fmt::Debug>(start: &Rc<RefCell<Node<T>>>) {
    let mut current = Some(start.clone());
    while let Some(node) = current {
        print!("{:?} ", node.borrow().value);
        current = node.borrow().next.clone();
    }
    println!();
}

fn traverse_backward<T: std::fmt::Debug>(end: &Rc<RefCell<Node<T>>>) {
    let mut current = Some(end.clone());
    while let Some(node) = current {
        print!("{:?} ", node.borrow().value);
        current = node.borrow().prev.clone();
    }
    println!();
}

here is the unit test:

#[test]
fn test_create(){
    let head = Rc::new(RefCell::new(Node::new(1)));
    insert_after(&head, 2);
    insert_after(&head.borrow().next.as_ref().unwrap(), 3);
    insert_before(&head, 0);
    
    println!("Traverse forward:");
    traverse_forward(&head.borrow().prev.as_ref().unwrap().clone());
    
    let tail = head.borrow().next.as_ref().unwrap().borrow().next.as_ref().unwrap().clone();
    println!("Traverse backward:");
    traverse_backward(&tail);
    
    println!("After deleting node with value 2:");
    // call with '&head.borrow().next.as_ref().unwrap()' reports Error: already borrowed: BorrowMutError
    // call with "&head" works ok. 
    delete(&head.borrow().next.as_ref().unwrap());
    traverse_forward(&head.borrow().prev.as_ref().unwrap().clone());    
}

Hello, @freedom

To fix this, you need to ensure that the temporary reference to the node you want to delete is dropped before you try to borrow it mutably inside the delete function. You can do this by using a let binding to store the temporary Ref so that it is released when it goes out of scope. Try This Code will be work

#[test]
fn test_create() {
    let head = Rc::new(RefCell::new(Node::new(1)));
    insert_after(&head, 2);
    insert_after(&head.borrow().next.as_ref().unwrap(), 3);
    insert_before(&head, 0);
    
    println!("Traverse forward:");
    traverse_forward(&head.borrow().prev.as_ref().unwrap().clone());
    
    let tail = head.borrow().next.as_ref().unwrap().borrow().next.as_ref().unwrap().clone();
    println!("Traverse backward:");
    traverse_backward(&tail);
    
    println!("After deleting node with value 2:");
    
    // Corrected code:
    // Create a new binding to the node you want to delete
    let node_to_delete = head.borrow().next.as_ref().unwrap().clone(); 
    // Now call the delete function with the new binding
    delete(&node_to_delete); 
    
    traverse_forward(&head.borrow().prev.as_ref().unwrap().clone());
}

2 Likes

thank you @relunsec very much , you are awesome. :beating_heart:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.