How can I bind a variable in the match hand when matching against a mutable reference?

I am match

structured and would like to use match guard. However, the structure is fluid, and the binding variables on the left side of the match arm seem to trigger a separate loan. This then causes compilation errors as you cannot have a second borrow (mutable or immutable) until the mutable borrow is done.

struct A(u8);

impl A {
    fn is_awesome(&self) -> bool { true }
}

struct Container(A);

impl Container {
    fn update(&mut self) {}

    fn do_a_thing(&mut self) {
        match *self {
            Container(ref a) if a.is_awesome() => self.update(),
            _ => {},
        }
    }
}

fn main() {}

      

error[E0502]: cannot borrow '*self' as mutable because 'self.0' is also borrowed as immutable
  --> src/main.rs:14:51
   |
14 |             Container(ref a) if a.is_awesome() => self.update(),
   |                       -----                       ^^^^ mutable borrow occurs here
   |                       |
   |                       immutable borrow occurs here
15 |             _ => {},
16 |         }
   |         - immutable borrow ends here

      

My current workaround is to duplicate the logic to compute the match defense before my match, then I can just use a boolean as my match defense. This does not address the obvious duplication issues:

fn do_a_thing(&mut self) {
    let awesome = match *self {
        Container(ref a) => a.is_awesome(),
    };

    match *self {
        Container(..) if awesome => self.update(),
        _ => {},
    }
}

      

+3


source to share


1 answer


When non-lexical lifetimes are enabled , your source code works as is.

Before non-sexual lives

In the name of safety, Rust prohibits different classes of things, even if they might work. This is one such case, and what you are trying to do is not and will never be possible.

You created a link to the content self

, but then you call self.update()

that requires a mutable link to self

. The language can efficiently inline update

and thus determine that it is safe to maintain this reference, but it is easy to demonstrate that the basic concept will not always work with this example of the flaw that the Rust compiler saves from:



struct A(u8);

struct Container(A);

impl Container {
    fn update(&mut self) {
        self.0 = A(0);
    }

    fn do_a_thing(&mut self) {
        let a = &self.0;
        let before = a.0;
        self.update();
        assert_eq!(before, a.0);
    }
}

fn main() {
    Container(A(1)).do_a_thing();
    // Panic: 1 != 0
}

      

If it were allowed to compile, it would cause panic, because the target a

, despite a

being an immutable reference, changed under you, which clearly cannot be done.

The Lucky C ++ Template Mentality is an example of trying something that may or may not work; with them, it is quite possible that a change deep in the inner part of a function could break its users so that they no longer compile. Rust has chosen not to go that route and therefore views each method as a strong isolation barrier. Any changes to the body of the function will never stop the compilation of code outside the method.

You cannot have any reference, changeable or otherwise, to anything internally self

while you call the &mut self

-requesting method on self

.

+4


source







All Articles