rust 可变地借用树的最后初始化的节点

cnh2zyt3  于 6个月前  发布在  其他
关注(0)|答案(1)|浏览(79)

我正在尝试在第一次访问节点时延迟初始化一个简单树。

我的树结构:

struct Tree {
    true_branch: Option<Box<Tree>>,
    false_branch: Option<Box<Tree>>,
}

字符串
为了在第一次访问时进行惰性初始化,我想返回一个Result<&mut Tree, &mut Tree>,如果节点已经初始化,则返回一个Ok(requested_node),或者返回一个Err(last_initialized_on_the_path_to_requested_node),以便惰性初始化可以从该节点继续。
获取一个节点,如果它被初始化,可以用get_mut很好地工作,但是我不能获取Result版本get_last_initialized_mut来编译。

impl Tree {
    fn get_mut(&mut self, mut directions: impl Iterator<Item = bool>) -> Option<&mut Self> {
        let mut current = self;
        loop {
            match directions.next() {
                None => break,
                Some(true) => {
                    current = current.true_branch.as_deref_mut()?;
                }
                Some(false) => {
                    current = current.false_branch.as_deref_mut()?;
                }
            }
        }
        Some(current)
    }
    
    /// This does not compile
    fn get_last_initialized_mut(&mut self, mut directions: impl Iterator<Item = bool>) -> Result<&mut Self, &mut Self> {
        let mut current = self;
        loop {
            match directions.next() {
                None => break,
                Some(true) => {
                    let next = current.true_branch.as_deref_mut();
                    if next.is_none() {
                        drop(next);
                        return Err(current);
                    } else {
                        current = next.unwrap();
                    }
                }
                Some(false) => {
                    let next = current.false_branch.as_deref_mut();
                    if next.is_none() {
                        drop(next);
                        return Err(current);
                    } else {
                        current = next.unwrap();
                    }
                }
            }
        }
        Ok(current)
    }
}

错误:

error[E0499]: cannot borrow `*current` as mutable more than once at a time
  --> src/lib.rs:36:36
   |
27 |     fn get_last_initialized_mut(&mut self, mut directions: impl Iterator<Item = bool>) -> Result<&mut Self, &mut Self> {
   |                                 - let's call the lifetime of this reference `'1`
...
33 |                     let next = current.true_branch.as_deref_mut();
   |                                ---------------------------------- first mutable borrow occurs here
...
36 |                         return Err(current);
   |                                    ^^^^^^^ second mutable borrow occurs here
...
52 |         Ok(current)
   |         ----------- returning this value requires that `current.true_branch` is borrowed for `'1`


我不明白的是,我在第35行删除了next,然后它说current仍然在第36行被借用,通过第33行的next借用。
我试过用枚举中断,然后根据中断类型返回到循环外,删除变量,但都不起作用。
Playground

eni9jsuy

eni9jsuy1#

在原始程序的每个匹配臂中,current的生存期(借用current)至少在匹配臂块结束之前结束:

let next = current.true_branch.as_deref_mut();
// borrow starts
if next.is_none() {
    drop(next);
    return Err(current);
} else {
    current = next.unwrap();
}
// borrow ends

字符串
我们可以将next的生存期限制在if let语句中,因为我们会检查Option枚举:

if let Some(ref mut next) = current.true_branch {
    // borrow of `current` only spans in this block
    current = next;
} else {
    // `current` is NOT borrowed here
    return Err(current);
}


现在,current的borrow只跨在if let语句的true分支中。在else分支中,current没有被borrowed。这意味着我们可以安全地在else分支中返回current
可复制的RustPlayground链接:https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=083e5901c967a764ed367bb58aab27fb

相关问题