如何向编译器传达借入仅发生在枚举的一半中

时间:2019-01-06 09:50:25

标签: rust borrow-checker

我有一个Parent,其中包含一个Option<Child>,每个Child,其中包含一个Target

struct MyError {}

struct Target {}

struct Child {
    target: Target,
}

struct Parent {
    child: Option<Child>,
}

创建ParentChild可能会失败:

impl Child {
    fn allocate_self() -> Result<Self, MyError> {
        Ok(Self { target: Target {} }) // could fail
    }
}

impl Parent {
    fn allocate_self() -> Result<Self, MyError> {
        Ok(Self { child: None }) // could fail
    }
}

我的目标是:

  1. 分配Parent,失败时返回错误。
  2. 分配Child,返回失败错误并释放Parent
  3. 成功返回&mut Target

到目前为止,我有:

impl Child {
    fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
        if this_opt.is_none() {
            *this_opt = Some(Self::allocate_self()?);
        }
        Ok(&mut this_opt.as_mut().unwrap().target)
    }
}

impl Parent {
    fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
        if this_opt.is_none() {
            *this_opt = Some(Self::allocate_self()?)
        }
        let this = this_opt.as_mut().unwrap();
        let result = Child::retrieve_target(&mut this.child);
        // GOAL: if Child::retrieve_target succeeds,
        //       return the result, otherwise turn ourselves back into a None
        if result.is_err() {
            drop(this_opt.take());
        }
        result
    }
}

问题是Parent::retrieve_target失败,并出现编译器错误:

error[E0499]: cannot borrow `*this_opt` as mutable more than once at a time
  --> src/lib.rs:44:18
   |
35 |     fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
   |                                  - let's call the lifetime of this reference `'1`
...
39 |         let this = this_opt.as_mut().unwrap();
   |                    -------- first mutable borrow occurs here
...
44 |             drop(this_opt.take());
   |                  ^^^^^^^^ second mutable borrow occurs here
45 |         }
46 |         result
   |         ------ returning this value requires that `*this_opt` is borrowed for `'1`

我尝试了各种方法来告诉编译器:Err的{​​{1}}部分不是借用Result而是没有成功。

一种解决方案是先执行分配,然后检索目标。但是,在我的用例中,我有多层(4层页表),因此理想情况下,一旦到达this_opt就可以返回。由于每一层都必须做大致相同的事情,因此我希望有可能使用一些简单的名称替换宏来创建多层结构。

这种书写方式(理想情况下安全,简洁)是可能的吗?

0 个答案:

没有答案