gpt4 book ai didi

rust - 为什么 RefCell :borrow_mut result in a BorrowMutError when used on both sides of a short-circuiting boolean AND (&&)?

转载 作者:行者123 更新时间:2023-12-03 11:25:50 63 4
gpt4 key购买 nike

我为 leetcode same tree problem 编写了这段代码:

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));
}
playground
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:39:23
我认为 &&是一个短路运算符,这意味着两个表达式不会同时存在,因此两个可变引用不应该同时存在。

最佳答案

一个最小化的例子:

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 , RefMut 类型的临时值被退回。来自 the reference :

The drop scope of the temporary is usually the end of the enclosing statement.


in expanded detail :

Apart from lifetime extension, the temporary scope of an expression isthe smallest scope that contains the expression and is for one of thefollowing:

  • The entire function body.
  • A statement.
  • The body of a if, while or loop expression.
  • The else block of an if expression.
  • The condition expression of an if or while expression, or a match guard.
  • The expression for a match arm.
  • The second operand of a lazy boolean expression.

如果扩展失败的代码,它将看起来像这样:
{
let t1 = x.borrow_mut();

*t1 && {
let t2 = x.borrow_mut();
*t2
}
}
这显示了双借是如何发生的。
正如您已经注意到的,您可以通过提前声明一个变量来解决这个问题。这保留了短路性质:
let a = *x.borrow_mut();
a && *x.borrow_mut();

关于rust - 为什么 RefCell :borrow_mut result in a BorrowMutError when used on both sides of a short-circuiting boolean AND (&&)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64879078/

63 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com