vendredi 16 avril 2021

Rust pattern match with capture

I can change the last element of a vec:

#[derive(Debug)]
enum Type {
    A,
    B,
    C,
}

fn main() {
    let mut v = vec![Type::A, Type::B, Type::B];
    
    match v.last_mut(){
        None => v.push(Type::A),
        Some(last) => *last = Type::C,
    }
    
    println!("{:?}", v)
}

==> prints [A, B, C].

But if my enum constants have data, I can't seem to capture them... For example:

#[derive(Debug)]
enum Type {
    A(i32),
    B(i32),
    C(i32),
}

fn main() {
    let mut v = vec![Type::A(0), Type::B(1), Type::B(2)];
    
    match v.last_mut(){
        None => v.push(Type::A(0)),
        Some(last @ Type::B(_)) => *last = Type::C(42),
        Some(Type::A(_)) | Some(Type::C(_)) => {}
    }
    
    println!("{:?}", v);
}

==> prints [A(0), B(1), C(42)]

The above works just because I put an _ inside Type::B(_). If I try to capture it to use in Type::C() with this line:

        Some(last @ Type::B(p)) => *last = Type::C(*p),

I get three weird errors:

error: borrow of moved value
  --> src/main.rs:13:14
   |
13 |         Some(last @ Type::B(p)) => *last = Type::C(*p),
   |              ----^^^^^^^^^^^-^
   |              |              |
   |              |              value borrowed here after move
   |              value moved into `last` here
   |              move occurs because `last` has type `&mut Type` which does not implement the `Copy` trait

error[E0658]: pattern bindings after an `@` are unstable
  --> src/main.rs:13:29
   |
13 |         Some(last @ Type::B(p)) => *last = Type::C(*p),
   |                             ^
   |
   = note: see issue #65490 <https://github.com/rust-lang/rust/issues/65490> for more information

error[E0382]: borrow of moved value
  --> src/main.rs:13:29
   |
13 |         Some(last @ Type::B(p)) => *last = Type::C(*p),
   |              ---------------^-
   |              |              |
   |              |              value borrowed here after move
   |              value moved here
   |
   = note: move occurs because value has type `&mut Type`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving the value
   |
13 |         Some(ref last @ Type::B(p)) => *last = Type::C(*p),
   |              ^^^

error: aborting due to 3 previous errors

I also tried to use the value inside last like a tuple, like this:

        Some(last @ Type::B(_)) => *last = Type::C(last.0),

without success as well:

error[E0609]: no field `0` on type `&mut Type`
  --> src/main.rs:13:57
   |
13 |         Some(last @ Type::B(_)) => *last = Type::C(last.0),
   |                                                         ^

error: aborting due to previous error

How could I make this work, i.e. capture the current value of B (a &mut i32), and pass it to C?

Aucun commentaire:

Enregistrer un commentaire