将基于Box的树结构适配为Rc+RefCell时如何处理“临时值丢失”错误?

2023-12-04

我创建了一个树,其类型定义类似于:

#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
    root: Option<Box<NodeBox<T>>>,
}

#[derive(Debug, Clone)]
struct NodeBox<T> {
    value: T,
    left: Option<Box<NodeBox<T>>>,
    right: Option<Box<NodeBox<T>>>,
}

impl<T: Ord> TreeBox<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        while let Option::Some(current_node) = node {
            match current_node.value.cmp(&value) {
                Ordering::Less => node = &mut current_node.right,
                Ordering::Equal => return false,
                Ordering::Greater => node = &mut current_node.left,
            }
        }

        *node = Option::Some(Box::new(NodeBox {
            value,
            left: Option::None,
            right: Option::None,
        }));

        return true;
    }
}

这非常有效,我对实施非常满意。但是我想存储从每个节点到其父节点的引用。经过一番研究我发现《Rust Book》中的一个章节描述一个实现使用RefCell and Weak结构。

有了这些知识,我的计划是更新上面的示例。我的想法是我可以替代Box<...> with Rc<RefCell<..>>。我的想法是,这些类型非常相似,因为它们都存储对某些数据结构的引用,唯一的区别是可以有多个Rc<RefCell<..>>指向该数据结构。我将我的实现更改为:

#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
    root: Option<Rc<RefCell<Node<T>>>>,
}

#[derive(Debug, Clone)]
struct Node<T> {
    value: T,
    left: Option<Rc<RefCell<Node<T>>>>,
    right: Option<Rc<RefCell<Node<T>>>>,
}

impl<T: Ord> Tree<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        while let Option::Some(current_node) = node {
            let cmp = current_node.borrow().value.cmp(&value);
            match cmp {
                Ordering::Less => node = &mut current_node.borrow_mut().right,
                Ordering::Equal => return false,
                Ordering::Greater => node = &mut current_node.borrow_mut().left,
            };
        }

        *node = Option::Some(Rc::new(RefCell::new(Node {
            value,
            left: Option::None,
            right: Option::None,
        })));

        return true;
    }
}

但是,这个更新的示例无法编译:

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:28:47
   |
28 |                 Ordering::Less => node = &mut current_node.borrow_mut().right,
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^     -
   |                                               |                             |
   |                                               |                             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 `RefMut<'_, 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

这两个示例都可以在操场.

我的例子是错误的,还是有什么我仍然不太明白的地方Rc<RefCell<_>>?


所以,你有一些问题。第一个是你试图引用一个Option包含一个生命周期很短的值,因为它与borrow() on RefCell。 (你也在尝试borrow_mut而一个borrow就位,这会引起恐慌。)值得庆幸的是,Rc使得获得引用的所有权变得便宜且容易Rc(这就是重点),所以这个问题可以通过存储来解决Option, not &Option,并自由克隆所包含的Rc。我们用Option::as_ref转换一个&Option<Rc<_>>进入一个Option<&Rc<_>>,然后变成Option<Rc<_>>通过映射Rc::clone超过它。

pub fn insert(&mut self, value: T) -> bool {
    let mut node = self.root.as_ref().map(Rc::clone);

    while let Some(current_node) = node {
        let current_node = current_node.borrow();
        let cmp = current_node.value.cmp(&value);
        let new_node = match cmp {
            Ordering::Less => &current_node.left,
            Ordering::Equal => return false,
            Ordering::Greater => &current_node.right,
        };
        node = new_node.as_ref().map(Rc::clone);
    }

    let node = &mut node;
    *node = Some(Rc::new(RefCell::new(Node {
        value,
        left: None,
        right: None,
    })));

    true
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将基于Box的树结构适配为Rc+RefCell时如何处理“临时值丢失”错误? 的相关文章

随机推荐

  • 如何在 Python 多处理中使用类?

    下面是一些示例代码 用于读取文件并将每一行相加 它应该将 0 到 20 之间的所有数字相加 然而 我总是得到一个结果0 可以看到中间计算成功了 为什么最后的结果是0 有一个更好的方法吗 我试图对更大 更复杂的输入文件进行更多计算 并存储一些
  • 当我最大化 JInternalFrame 时 JInternalFrame 上的示例程序 JMenubar

    Hi I need an Example program in which When i maximize the JInternalFrame the JMenuBar of JFrame should set on JInternalF
  • iPad应用程序可以直接启动另一个应用程序吗?

    我想知道是否可以直接从另一个应用程序中启动 iPad 应用程序 例如 我可以编写一个登录页面 该页面也会带您进入桌面类型页面 您可以在其中选择要运行的应用程序 然后以新线程的方式启动该应用程序 我不确定这是否可行 我只是对新的 iOS 多任
  • 我怎样才能访问放置在 WEB-INF 文件夹中的文件

    我是java新手 有一个奇怪的问题 我在 WEB INF 文件夹中创建一些文件夹 主题 js css 并将我的文件放入此文件夹中 在index jsp中我通过以下方式使用css文件 效果很好 但在 style css 文件中 我有一个 di
  • 如何在Javascript中获取`background-color`属性值? [复制]

    这个问题在这里已经有答案了 fiddle 以下代码警告空字符串 HTML div test div CSS test background color f00 SCRIPT alert document getElementById tes
  • 验证 Assertj 中是否已调用断言

    我正在阅读使用 Assertj 来验证结果的测试类 有时 我会发现一个没有断言的assertThat assertThat object getField 是否有可能在开发周期的某个地方识别这些类 我的第一个猜测是使用自定义声纳规则 尽管我
  • 无法使用 Mac x86 程序集将 .data 中的变量移动到寄存器

    我用 AT T 语法编写了一小段程序集 目前已在 data部分 但是 当我尝试将这些变量中的任何一个移动到寄存器时 例如 eax 一个错误来自gcc被提出 代码和错误信息如下 data x int 14 y int 4 str string
  • Java静态序列化规则?

    我正在使用一些静态方法和字段进行保存状态序列化 我可以发誓尽管序列化和静态造成了混乱 我应该让所有静态都是瞬态的吗 增加通话量会恢复正常吗 statics 是隐含的transient 所以你不需要这样声明它们 序列化是为了序列化实例 not
  • x86_64 程序集 - 尝试在 x64 程序集中编辑数组内的字节时出现段错误

    我遵循的教程适用于 x86 是使用 32 位汇编编写的 我尝试在学习 x64 汇编的过程中遵循该教程 直到本课为止 一切都进展顺利 我有以下简单的程序 它只是尝试修改字符串中的单个字符 它编译得很好 但运行时出现段错误 section te
  • 使用 firebase 进行 JUnit 类测试

    我试图JUnit测试这个类 public class WeekListActivity extends AppCompatActivity implements AdapterView OnItemClickListener private
  • 如何解决此错误“webelement 不支持索引”[webdriver][python]

    我正在进行 xpath 搜索 page driver find element by xpath td class mceIframeContainer mceFirst mceLast 1 这给了我在 firebug 中所需的第一类项目
  • Google Map API V3:MarkerClusterer 不会分解为标记

    我有一个应用程序 我使用 Google Map API 来显示用户使用其纬度 经度发布的帖子的标记 我使用了 MarkerClusterer 功能来更好地组织标记 该功能可以工作 但存在一些错误 本质上 我一直在家里对此进行测试 因此所有测
  • 我对 Sails.js 水线一对一关联逻辑感到困惑

    所以我感到困惑的原因是因为我是一名 PHP 开发人员并且经常使用 Laravel 和 FuelPHP 我真正不明白的是协会本身 我的意思是 我想创建一个基本的 hasOne BelongsTo 逻辑 其中包含以下内容 用户只有一份个人资料
  • 在 Scala 中计算最多 5 的中位数

    因此 在回答其他一些问题时 我偶然发现计算 5 的中位数的必要性 现在 有一个类似的问题用另一种语言 但我想要一个 Scala 算法 但我不确定我对我的算法是否满意 这是一个不可变的 Scala 版本 它具有最少的比较次数 6 并且看起来不
  • 由于 reticulate_python 导致闪亮应用程序部署出现问题

    我有一个应用程序想要部署在shinyapps io 上 我认为值得注意的是 应用程序中的数据是从 athena 的数据库中提取的 我用了这个包Rathena连接到数据库以及所有用于从我的计算机本地运行良好的内容 但是 我尝试将其部署到shi
  • 如何正确隐藏这些广告横幅?

    Sprite Kit 游戏 我希望在游戏过程中隐藏我的广告横幅 我已经将我的项目设置为包含 iAd 和 AdMob 广告横幅 在添加 AdMob SDK 和 AdMob 广告代码之前 当我想要隐藏 iAd 横幅时 隐藏它没有任何问题 现在由
  • 具有导出选项(如数据表)的等效单个 Html 文件

    我使用 DataTables 使用静态数据创建了一个 HTML 表 带有导出选项 搜索 分页 plnkr co edit n3cbx8GrGoJtOpgbxE32 p preview 类似的示例或工作 html 可在 angular ui
  • 登录对话框 PyQt

    当客户询问我是否可以在应用程序启动时实现某种登录表单时 我几乎完成了我的应用程序 到目前为止 我已经设计了用户界面 并修改了实际的执行 用户名和密码目前无关紧要 class Login QtGui QDialog def init self
  • 我无法使用 ctypes 访问 C++ 类属性

    我正在使用 ctypes 为 C 库开发一种 Python API 到目前为止 一切都很顺利 但是 我将操作系统从 Ubuntu 20 4 LTS 升级到 22 04 现在使用 Python3 10 6 和 g 11 3 0 但即使使用 g
  • 将基于Box的树结构适配为Rc+RefCell时如何处理“临时值丢失”错误?

    我创建了一个树 其类型定义类似于 derive Debug Clone pub crate struct TreeBox