nova rusta
nova rusta

Reputation: 13

How do I use match to modify a mutable variable in a way that is guaranteed to be non-exhaustive and not require clone?

When using a match to modify a mutable variable, I haven't found a way to use match in a way that is guaranteed to be non-exhaustive and not requiring clone.

struct Stuff {
    num: u32,
    thing: bool,
}

enum Bar {
    Nothing,
    SomeStuff(Stuff),
    AlsoNothing,
}

fn main() {
    let mut things = vec![Bar::SomeStuff(Stuff {
        num: 2,
        thing: false,
    })];

    for x in things.iter_mut() {
        *x = match *x {
            Bar::Nothing => Bar::AlsoNothing,
            Bar::AlsoNothing => Bar::SomeStuff(Stuff {
                num: 3,
                thing: true,
            }),
            Bar::SomeStuff(thing) => panic!("not sure"),
        }
    }
}
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:19:20
   |
19 |         *x = match *x {
   |                    ^^ cannot move out of borrowed content
...
25 |             Bar::SomeStuff(thing) => panic!("not sure"),
   |                            ----- hint: to prevent move, use `ref thing` or `ref mut thing`

My intent is to write Bar::SomeStuff(thing) => Bar::SomeStuff(thing) and effectively leave it unchanged, but I cannot move through with a borrow or a reference.

Bar::SomeStuff(thing.clone()) could work, but copying a big struct could be very expensive.

Removing the *x = and changing to () could also work, but I am only returning a Bar enum so having the compiler check the return type is something I hope to keep.

Upvotes: 1

Views: 575

Answers (1)

hellow
hellow

Reputation: 13450

If you want to pass a value unchanged, just capture the match with a variable and pass that back, e.g.

fn foo(a: u32) -> u32 {
    match a {
        0 => 1,
        1 => 2,
        e => e,
    }
}

In your case, I would move the variable assignment into the match arms

for x in things.iter_mut() {
    match x {
        Bar::Nothing => *x = Bar::AlsoNothing,
        Bar::AlsoNothing => *x = Bar::SomeStuff(Stuff { num: 3, thing: true }),
        _ => {},
    }
}

Upvotes: 2

Related Questions