我为leetcode相同树问题编写了此代码:
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));
}
Run Code Online (Sandbox Code Playgroud)
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));
}
Run Code Online (Sandbox Code Playgroud)
我认为&&
是一个短路运算符,这意味着这两个表达式不会同时存在,因此不应同时存在两个可变引用。
一个最小化的例子:
use std::cell::RefCell;
fn main() {
let x = RefCell::new(true);
*x.borrow_mut() && *x.borrow_mut();
}
Run Code Online (Sandbox Code Playgroud)
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:8:27
Run Code Online (Sandbox Code Playgroud)
当您调用 时RefCell::borrow_mut
,将RefMut
返回一个临时值类型。从参考:
临时文件的删除范围通常是封闭语句的结尾。
并详细说明:
除了生命周期延长之外,表达式的临时作用域是包含该表达式的最小作用域,适用于以下情况之一:
- 整个函数体。
- 一份声明。
- 一个的本体
if
,while
或loop
表达。- 表达式的
else
块if
。if
orwhile
表达式或match
守卫的条件表达式。- 匹配臂的表达式。
- 惰性布尔表达式的第二个操作数。
如果展开失败的代码,它将看起来像这样:
{
let t1 = x.borrow_mut();
*t1 && {
let t2 = x.borrow_mut();
*t2
}
}
Run Code Online (Sandbox Code Playgroud)
这显示了双重借用是如何发生的。
正如您已经注意到的,您可以通过提前声明一个变量来解决这个问题。这保留了短路特性:
let a = *x.borrow_mut();
a && *x.borrow_mut();
Run Code Online (Sandbox Code Playgroud)