Pattern matching problem

Hello. I'm trying to pattern-match an enum alongside a passed value in a loop, and have a mutable reference to a field in the enum. However, I can't seem to figure out the correct way to write this.

This is where I'm currently at:

use std::collections::HashMap;

enum Foo {
    One(HashMap<u8, u8>),
    Two,
}

impl Foo {
    fn bar(&mut self, a: u8) {
        for i in 0..2 {
            match (self, a) {
                (Foo::One(h), _) => {
                    h.get_mut(&0);
                }
                (Foo::Two, _) => {}
            }
        }
    }
}

fn main() {}

This code results in the compiler complaining about self being moved in the previous iteration of the loop.

Trying to do &self in the match statement makes h.get_mut() fail

Trying to do &mut self in the match statement fails because "the binding is already a mutable borrow"

What do?

Anyway, just spotted this thread: Matching on `&mut self` without moving it

Seems like the solution to my problem. Didn't notice it pop up in the suggestions when I was writing the post. I will try the solution on my real project and then update this thread

Yep, the thread linked indeed has the solution in it. Here's that solution applied to the sample code I provided:

use std::collections::HashMap;

enum Foo {
    One(HashMap<u8, u8>),
    Two,
}

impl Foo {
    fn bar(&mut self, a: u8) {
        for i in 0..2 {
            match (&mut *self, a) {
                (Foo::One(h), _) => {
                    h.get_mut(&0);
                }
                (Foo::Two, _) => {}
            }
        }
    }
}

fn main() {}
1 Like

The weird thing about reborrows is that they can and do happen automatically and invisibly, but only when the result type is known to be a mutable reference, for example, when passing self to another function that takes &mut self. The match doesn’t impose such an exact type, so you need the explicit reborrow. You could also, if you wanted to for some reason, force the implicit reborrow with a type annotation:

let this: &mut Foo = self;
match (this, a) {

There’s no particular reason to do that instead of &mut *self, however.

2 Likes