返回包含引用的结果时,不能一次多次借用 `*self` 作为可变变量

cYr*_*rus 5 rust borrow-checker

为什么以下无效,我应该怎么做才能使其工作?

struct Foo;

impl Foo {
    fn mutable1(&mut self) -> Result<(), &str> {
        Ok(())
    }

    fn mutable2(&mut self) -> Result<(), &str> {
        self.mutable1()?;
        self.mutable1()?;
        Ok(())
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码产生:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/lib.rs:10:9
   |
8  |     fn mutable2(&mut self) -> Result<(), &str> {
   |                 - let's call the lifetime of this reference `'1`
9  |         self.mutable1()?;
   |         ----           - returning this value requires that `*self` is borrowed for `'1`
   |         |
   |         first mutable borrow occurs here
10 |         self.mutable1()?;
   |         ^^^^ second mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)

有很多问题已经有相同的错误,但我不能用它们来解决这个问题,因为它?是导致问题的隐式返回的存在,没有?代码成功编译,但有警告。

操场

She*_*ter 8

这与从 HashMap 或 Vec 返回引用导致借用持续超出其所在范围中讨论的问题相同. 通过生命周期省略, 的生命周期&str与 的生命周期相关&self。编译器不知道在Ok返回an 的情况下不会使用借用。它过于保守并且不允许使用此代码。这是当前借用检查器实现的限制。

如果您确实需要将Err变体的生命周期与Foo实例的生命周期相关联,那么在安全 Rust 中没有什么可做的(不安全 Rust 是另一回事)。但是,在您的情况下,您似乎不太可能&str与 的生命周期相关联self,因此您可以使用显式生命周期来避免该问题。例如,a&'static str是常见的基本错误类型:

impl Foo {
    fn mutable1(&mut self) -> Result<(), &'static str> {
        Ok(())
    }

    fn mutable2(&mut self) -> Result<(), &'static str> {
        self.mutable1()?;
        self.mutable1()?;
        Ok(())
    }
}
Run Code Online (Sandbox Code Playgroud)

因为它是由提供的隐式回报的存在 ?

并非如此,因为具有显式返回的相同代码具有相同的问题:

fn mutable2(&mut self) -> Result<(), &str> {
    if let Err(e) = self.mutable1() {
        return Err(e);
    }
    if let Err(e) = self.mutable1() {
        return Err(e);
    }
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)
impl Foo {
    fn mutable1(&mut self) -> Result<(), &'static str> {
        Ok(())
    }

    fn mutable2(&mut self) -> Result<(), &'static str> {
        self.mutable1()?;
        self.mutable1()?;
        Ok(())
    }
}
Run Code Online (Sandbox Code Playgroud)