3

In the following program, I attempt to create a change function which mutably modifies the constructor of a datatype:

enum Typ {
    Foo { x: u32 },
    Bar { x: u32 },
}
use Typ::*;

fn change(val: &mut Typ) {
    match val {
        &mut Foo { ref mut x } => *val = Bar { x: *x },
        &mut Bar { ref mut x } => *val = Foo { x: *x },
    }
}

fn main() {
    let mut val = Foo { x: 1 };
    change(&mut val);
    println!("Hello, world!");
}

That does not work:

error[E0506]: cannot assign to `*val` because it is borrowed
 --> src/main.rs:9:35
  |
9 |         &mut Foo { ref mut x } => *val = Bar { x: *x },
  |                    ---------      ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `*val` occurs here
  |                    |
  |                    borrow of `*val` occurs here

error[E0506]: cannot assign to `*val` because it is borrowed
  --> src/main.rs:10:35
   |
10 |         &mut Bar { ref mut x } => *val = Foo { x: *x },
   |                    ---------      ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `*val` occurs here
   |                    |
   |                    borrow of `*val` occurs here

Is it possible to modify something inside its pattern-matching clause?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
MaiaVictor
  • 51,090
  • 44
  • 144
  • 286
  • @Shepmaster the title is much better phrased that way, but wouldn't that avoid it being found by people searching for "modify" "inside" "pattern-matching"? – MaiaVictor Sep 17 '18 at 15:41
  • 2
    I changed it because the original form sounds much more like you are asking if you modify something in the `&mut Foo { ref mut x }` part, not the `=> ...` part. – Shepmaster Sep 17 '18 at 15:43
  • That being said, your old title can replace your last sentence, which I've now done. – Shepmaster Sep 17 '18 at 15:44
  • 1
    @Shepmaster I see you deleted your answer in favor of redirecting to another question, but I should point out that my question/code was much simpler and your answer was more straight-forward. The other one is quite complex and confusing. I'm glad I've seen it before your deletion. I wonder if S.O. has guidelines for redirecting duplicates even when the more recent thread is more pedagogical. – MaiaVictor Sep 17 '18 at 15:53
  • 1
    I've already updated my other answer to provide a simpler reproduction ;-) Thank you for taking the time to make a better MCVE than the existing question, however! I chose to duplicate because the existing answers have multiple solutions for working around the current limitation, which people tend to appreciate. – Shepmaster Sep 17 '18 at 15:54
  • 1
    @Shepmaster hmm yea, but I'm thinking from the perspective of someone Googling, arriving to my question, then arriving to that other question, then seeing that chunk of code on OP and either thinking "well this is someone's personal code that is probably not related to my problem" and closing the tab, or reading through the whole thing just to get to your simplified answer. (In any case, if a future reader is having this problem, please click the link and skip directly to Shepmaster's answer.) – MaiaVictor Sep 17 '18 at 15:56
  • 3
    I'd like to point out that although NLL fixes this problem, you are still moving out of a reference in `*x`, which means that `x` must be `Copy`. If `x` is `Copy`, you can delete the `ref mut` in the pattern and [it will work in stable Rust](https://play.rust-lang.org/?gist=500f66210535a079d51eee27dbfb73b9&version=stable&mode=debug&edition=2015). – trent Sep 17 '18 at 15:57
  • 1
    Related: [Change enum variant while moving the field to the new variant](https://stackoverflow.com/q/36557412/155423) – Shepmaster Sep 17 '18 at 16:01

0 Answers0