为什么 RefCell:borrow_mut 在短路布尔 AND (&&) 两侧使用时会导致 BorrowMutError?

2024-03-27

我为 leetcode 编写了这段代码同一棵树问题 https://leetcode.com/problems/same-tree/:

use std::cell::RefCell;
use std::rc::Rc;

// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

struct Solution;

impl Solution {
    pub fn is_same_tree(
        p: Option<Rc<RefCell<TreeNode>>>,
        q: Option<Rc<RefCell<TreeNode>>>,
    ) -> bool {
        match (p, q) {
            (None, None) => true,
            (Some(p), Some(q)) if p.borrow().val == q.borrow().val => {
                // this line won't work, it will cause BorrowMutError at runtime
                // but the `a & b` version works
                return (Self::is_same_tree(
                    p.borrow_mut().left.take(),
                    q.borrow_mut().left.take(),
                )) && (Self::is_same_tree(
                    p.borrow_mut().right.take(),
                    q.borrow_mut().right.take(),
                ));

                let a = Self::is_same_tree(p.borrow_mut().left.take(), q.borrow_mut().left.take());
                let b =
                    Self::is_same_tree(p.borrow_mut().right.take(), q.borrow_mut().right.take());
                a && b
            }
            _ => false,
        }
    }
}

fn main() {
    let p = Some(Rc::new(RefCell::new(TreeNode {
        val: 1,
        left: Some(Rc::new(RefCell::new(TreeNode::new(2)))),
        right: Some(Rc::new(RefCell::new(TreeNode::new(3)))),
    })));
    let q = Some(Rc::new(RefCell::new(TreeNode {
        val: 1,
        left: Some(Rc::new(RefCell::new(TreeNode::new(2)))),
        right: Some(Rc::new(RefCell::new(TreeNode::new(3)))),
    })));

    println!("{:?}", Solution::is_same_tree(p, q));
}
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:39:23

I think &&是一个短路运算符,这意味着两个表达式不会同时存在,因此两个可变引用不应同时存在。


一个最小化的例子:

use std::cell::RefCell;

fn main() {
    let x = RefCell::new(true);
    *x.borrow_mut() && *x.borrow_mut();
}
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:8:27

你打电话时RefCell::borrow_mut https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.borrow_mut, 类型的临时值RefMut https://doc.rust-lang.org/std/cell/struct.RefMut.html被返回。从参考资料 https://doc.rust-lang.org/1.47.0/reference/expressions.html#temporaries:

临时的删除范围通常是封闭语句的末尾。

And 详细展开 https://doc.rust-lang.org/1.47.0/reference/destructors.html#temporary-scopes:

除了生命周期延长之外,表达式的临时范围是 包含表达式且适用于其中之一的最小范围 下列的:

  • 整个函数体。
  • 一份声明。
  • 一个的身体if, while or loop表达。
  • The else块的if表达。
  • 的条件表达式if or while表达式,或match guard.
  • 火柴臂的表达式。
  • a 的第二个操作数惰性布尔表达式 https://doc.rust-lang.org/1.47.0/reference/expressions/operator-expr.html#lazy-boolean-operators.

如果展开的话,失败的代码将如下所示:

{
    let t1 = x.borrow_mut();

    *t1 && {
        let t2 = x.borrow_mut();
        *t2
    }
}

这显示了双重借用是如何发生的。

正如您已经注意到的,您可以通过提前声明变量来解决此问题。这保留了短路性质:

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

为什么 RefCell:borrow_mut 在短路布尔 AND (&&) 两侧使用时会导致 BorrowMutError? 的相关文章

随机推荐

  • 单实例登录实现

    我在我的项目 在 ASP NET 2 0 中构建的 Web 应用程序 中遇到了一个严重的问题 如下所述 假设我已经给出了用户 ID singh nirajan 并且用户说 User1 使用该用户 ID 登录到系统 现在我的要求是每当其他用户
  • javascript 将 int 转换为 float

    我有一个变量 var fval 4 现在我想输出为 4 00 JavaScript 只有一个Number存储浮点值的类型 没有 int Edit 如果要将数字格式化为小数点后两位数字的字符串 请使用 4 toFixed 2
  • 如何使用 Jackson 将字符串反序列化为自定义对象?

    我有一个想要解析的 JSON name john 我必须使用以下层次结构 这些类是不可变的 我必须通过静态工厂方法访问它们 这是必要的 因此建议对其中任何一个进行修改都是没有意义的Name or Person class Name stat
  • 如何添加 CSS3 过渡并显示 HTML5 详细信息/摘要标签?

    仅使用CSS3 有没有一种方法可以在页面上添加漂亮的淡入和从左滑动过渡效果DETAILS SUMMARY reveal 有关此新标签的演示 请参阅此演示 details transition height 3s ease in
  • c3p0如何关闭所有数据库连接并在需要时重新打开它们?

    我有一个 TimerTask 每天运行一次 大约 1 或 2 小时 每次运行时 它都会创建数百个线程来为 MySQL 数据库中的每个表执行一些计算工作 我使用c3p0作为数据库源连接池 每个线程在计算前获取连接 计算后关闭连接 我设置连接池
  • iOS 8 - 视频和声音文件无法从主屏幕 Web 应用程序播放

    我有一个 HTML5 Web 应用程序 它使用 JWPlayer 来嵌入视频和播客 这在 iOS 7 中运行良好 无论是在 Safari 中还是作为 Web 应用程序保存到主屏幕时 在 iOS 8 中 视频和声音文件也可以在 Safari
  • 使用 sed 为选项卡添加背景颜色?

    是否可以使用 sed 更改选项卡 或任何其他文本 的背景颜色 以便 例如 我可以运行如下所示的内容 somefunction sed e s some pattern set bg color 1 unset bg color g Yes
  • QNetworkAccessManager和HTTP持久连接

    HTTP 1 1 默认支持持久连接 因此我想使用发出第一个 HTTP 请求时设置的相同连接来发送第二个 http 请求 如何通过Qt来实现这一点 如果我只是在第一个请求完成后发出第二个请求 如下所示 manager gt get QNetw
  • 当维度在类实例化时未定义时,如何将浮点数组声明为 Objective-C 中的类变量?

    在 Java 中 它看起来像这样 class Foo float array Foo instance new Foo instance array new float 10 你可以只使用一个指针 float array Allocate
  • 列出Innodb全文索引的单词

    在 Mysql Innodb 中 我创建了一个全文索引 是否有一个查询可以用来检索全文索引中包含的所有单词的列表 我的想法是使用一个文本字段来保存标签列表的 json 转储 我可以使用全文查询来检索与标签匹配的行 它有效 剩下的问题是检索索
  • ctypes 结构中的默认值

    在 ctypes 结构中 是否可以指定默认值 例如 使用常规 python 函数 您可以执行以下操作 def func a b 2 print a b 这将允许这种行为 func 1 prints 3 func 1 20 prints 21
  • 从传统的基于 XUL 的附加组件中访问附加 SDK?

    我有一个大型且复杂的基于 XUL 的插件 我需要使用插件 SDK 中的一些函数 这可能吗 如果是这样 是否有人有工作示例代码 最好使用 page worker 模块 以下是 devtools 的做法 但某些模块会阻塞 明显的候选者是self
  • 无法访问viewBinding

    我现在正在 Kotlin 中使用 viewBinding here is my build gradle 启用 ViewBinding 并具有自动导入 ViewBinding 依赖项 but Android Studio still sho
  • 如何更好地组织数据库以适应用户状态的变化

    我关注的用户可以是 未确认 或 已确认 后者意味着他们获得完全访问权限 而前者意味着他们正在等待主持人的批准 我不确定如何设计数据库来解释这种结构 我的一个想法是拥有两个不同的表 confirmedUser 和 unconfirmedUse
  • 获取parent.location.url - iframe - 从子级到父级

    我得到了一个在 iframe 中显示的页面 我需要从该页面 子页面 获取带有js的parent location url 两个站点位于不同的域中 我想 警报 父 位置 url 但我收到这个错误 权限被拒绝http 父域 http paren
  • 通过 ASP.NET Identity 和 Autofac OWIN 集成进行授权

    在这个问题的底部添加了更新 我有一个 Web 应用程序 它使用 MVC5 和 WebAPI2 以及 Autofac for DI 该应用程序使用 ASP NET Identity 和 oAuth 不记名令牌 尽管后者可能不是重点 这一切都运
  • C#:存储百分比,50 还是 0.50?

    当在变量中保存百分比值时 会优先将它们保存为整数还是分数 也就是说 变量应该保存 0 到 100 之间的数字还是 0 00 到 1 00 之间的数字 在任何一种情况下 保存值的变量都是十进制类型 我正在交互的数据库恰好将它们存储为 0 到
  • Ionic 项目中的 GSAP

    如何将 GSAP 库导入到 Ionic 项目中 只是使用npm 安装 gsap当我通过导入时不起作用 import TweenMax TimelineMax from gsap 我使用打字稿 谢谢 你不需要打字 我在几个项目中使用过它 所有
  • 克服 Windows 用户对象句柄限制

    我正在寻找在构建重量级 Windows 界面时处理用户对象句柄限制的高级策略 请解释您如何使用 SWT 或直接 Windows GUI API 克服或绕过此问题 我唯一不感兴趣的是优化小部件使用的策略 因为我已经广泛地这样做了 但它并没有解
  • 为什么 RefCell:borrow_mut 在短路布尔 AND (&&) 两侧使用时会导致 BorrowMutError?

    我为 leetcode 编写了这段代码同一棵树问题 https leetcode com problems same tree use std cell RefCell use std rc Rc Definition for a bina