when tried impl a double linked list in rust, i found below unexpected error
if let Some(link) = self.tail.take() {
let x = link.borrow_mut();
link.borrow_mut().next = Some(node.clone());
} else { ... }
here link is inferred to be Rc<RefCell<Node<..>>>
and compiler says:
Cannot borrow immutable local variable
link
as mutable.
After tried, I guess when use std::borrow::BorrowMut
, the error occurs.
// compiles
fn test1() {
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
// doesn't compile
fn test2() {
use std::borrow::BorrowMut; // inserted this import!
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
here test2()
fails to be compiled. I wanna know why it works this way.
What you want to call is the method RefCell::borrow_mut()
.
However, a
is a Rc
and not a RefCell
, so it has no borrow_mut
method. This is where auto-dereferencing enters the picture. Because Rc<RefCell<T>>
implements the Deref
trait, it can be automatically dereferenced to a &RefCell<T>
at method calls, and that's exactly what happens in the first test.
Now, if we import the BorrowMut
trait, the test stops working. This is because the BorrowMut
trait also has a method called borrow_mut
, which is implemented for all types:
impl<T: ?Sized> BorrowMut<T> for T { ... }
This means that there is now a borrow_mut
method available for Rc
, so no auto-dereferencing occurs, and our code calls the wrong method.
The most comprehensive explanation of how auto-dereferencing works is in this SO answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With