// Definition for singly-linked list.
// pub struct ListNode { pub val: i32, pub next: Option<Box<ListNode>> }
impl Solution {
pub fn remove_elements(root: Option<Box<ListNode>>, target: i32) -> Option<Box<ListNode>> {
let mut root = root;
while let Some(n) = root.as_ref() {
if n.val == target {
root = root.unwrap().next;
} else {
break;
}
}
let mut ptr = &mut root;
while let Some(n) = ptr {
while let Some(sub) = n.next.as_mut() {
if sub.val == target {
n.next = sub.next.take();
} else {
break;
}
}
ptr = &mut n.next;
}
root
}
}
The statement let mut root = root; employs variable shadowing to bind the ownership of the immutable root parameter to a mutable variable, enabling in-place modifications during linked list traversal.
In the initial loop, n holds an immutable reference to root. The subsequent line root = root.unwrap().next modifies root while n is seemingly still active. This is permitted due to Non-Lexical Lifetimes (NLL). The borrow tied to n expires after its final usage in the condition n.val == target, clearing the way for root to be consumed and reassigned.
The declaration let mut ptr = &mut root; establishes a mutable tracker. The variable ptr is mutable, its type is a mutable reference &mut Option<Box<ListNode>>, and it borrows root mutably.
Within while let Some(n) = ptr, an implicit reborrow occurs. n becomes a mutable reborrow of the Box<ListNode> inside the Option. While a reborrow is active, the original borrowed reference (ptr) cannot be accessed, preventing overlapping mutable aliases.
The inner loop while let Some(sub) = n.next.as_mut() takes a mutable reference to the next field of n. Although sub and n.next both refer to the same underlying memory location, Rust permits borrowing distinct structural fields, and sub acts as a reborrow of the pointer held in n.next.
The assignment n.next = sub.next.take() might appear to use sub and mutate n.next simultaneously. However, Rust evaluates the right-hand side of an assignment before the left-hand side. The borrow on sub concludes once sub.next.take() executes, well before the mutation of n.next occurs.
Finally, ptr = &mut n.next; updates the mutable reference. The reborrow associated with n terminates at this point in the loop iteration, freeing ptr to be reassigned to a new mutable reference targeting the subsequent node.