首页 > 解决方案 > 如何解决“创建一个仍在使用时释放的临时变量”?

问题描述

我正在尝试使用循环Debug为我的自定义实现。List<T>while

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

我知道我正在参考一个临时值r,这很糟糕。有没有围绕这个问题的优雅和惯用的解决方案?

Rust 代码后跟 Rustaceans 是否有任何借用模式?我知道一种这样的模式是std::mem::replace拥有一个价值,它只有在我们拥有时才有效&mut T,有人称之为印第安纳琼斯模式

标签: rustborrow-checker

解决方案


在 Rust 用户论坛上问了同样的问题,得到了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, "[]")
    }
}

这样做的原因是borrow()返回一个带有析构函数的守卫,并且您只能RefCell在该守卫仍处于活动状态时访问引用。因此,如果不克隆 an Rc,您将需要保留每次迭代的所有守卫,但循环会在前进到下一次迭代时破坏前一个守卫。Rc克隆让您无需通过防护即可访问下一个节点,从而回避了这个问题。


推荐阅读