Reputation: 1533
I am trying to implement Debug
for my custom List<T>
using a while
loop.
use std::cell::RefCell;
use std::rc::Rc;
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
struct Node<T> {
val: T,
next: Link<T>,
}
struct List<T> {
head: Link<T>,
tail: Link<T>,
len: usize,
}
use std::fmt;
impl<T: fmt::Debug> fmt::Debug for List<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut temp = &self.head;
while let Some(r) = temp {
write!(f, "{:?} -> ", r.borrow().val);
temp = &r.borrow().next; // ERROR
}
write!(f, "[]")
}
}
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:21:21
|
21 | temp = &r.borrow().next; // ERROR
| ^^^^^^^^^^ -
| | |
| | temporary value is freed at the end of this statement
| | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, Node<T>>`
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
|
= note: consider using a `let` binding to create a longer lived value
I know that I am taking a reference of a temporary value r
, which is bad. Is there an elegant and idiomatic solution around this problem?
Are there any borrow patterns for Rust code followed by Rustaceans? I know one such pattern is std::mem::replace
to take ownership of a value, which works only when we have &mut T
, some call it Indiana Jones Pattern 🙂
Upvotes: 7
Views: 3536
Reputation: 1533
I asked the same question on the Rust User's Forum and got an answer from alice:
impl<T: fmt::Debug> fmt::Debug for List<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut temp = self.head.clone();
while let Some(r) = temp {
write!(f, "{:?} -> ", r.borrow().val);
temp = r.borrow().next.clone();
}
write!(f, "[]")
}
}
The reason for this is that
borrow()
returns a guard with a destructor, and you can only access references into theRefCell
while that guard is still active. So without cloning anRc
, you would need to keep all the guards from each iteration around, but the loop destroys the previous guard when advancing to the next iteration. AnRc
clone lets you access the next node without going through the guard, hence sidestepping the issue.
Upvotes: 2