Antoxyde
Antoxyde

Reputation: 535

Why do I get an error when pattern matching a struct-like enum variant with fields?

I can't get rid of an error on this code:

#[derive(PartialEq, Copy, Clone)]
pub enum OperationMode {
    ECB,
    CBC { iv: [u8; 16] },
}

pub struct AES {
    key: Vec<u8>,
    nr: u8,
    mode: OperationMode,
}

impl AES {
    pub fn decrypt(&mut self, input: &Vec<u8>) {
        match self.mode {
            OperationMode::ECB => {},
            OperationMode::CBC(_) => {},
        };
    }
}

The pattern matching at the end of the decrypt function gives an error:

error[E0532]: expected tuple struct/variant, found struct variant `OperationMode::CBC`
  --> src/main.rs:17:13
   |
17 |             OperationMode::CBC(_) => {},
   |             ^^^^^^^^^^^^^^^^^^ did you mean `OperationMode::CBC { /* fields */ }`?

It tells me to look at the output of rustc --explain E0532 for help, which I did.

They show this example of wrong code:

enum State {
    Succeeded,
    Failed(String),
}

fn print_on_failure(state: &State) {
    match *state {
        // error: expected unit struct/variant or constant, found tuple
        //        variant `State::Failed`
        State::Failed => println!("Failed"),
        _ => ()
    }
}

In this example, the error occurs because State::Failed has a field which isn't matched. It should be State::Failed(ref msg).

In my case I'm matching the field of my enum because I'm doing OperationMode::CBC(_). Why does the error happen?

Upvotes: 41

Views: 28516

Answers (1)

Shepmaster
Shepmaster

Reputation: 430821

Enum variants have three possible syntaxes:

  • unit

    enum A { One }
    
  • tuple

    enum B { Two(u8, bool) }
    
  • struct

    enum C { Three { a: f64, b: String } }
    

You have to use the same syntax when pattern matching as the syntax the variant was defined as:

  • unit

    match something {
        A::One => { /* Do something */ }
    }
    
  • tuple

    match something {
        B::Two(x, y) => { /* Do something */ }
    }
    
  • struct

    match something {
        C::Three { a: another_name, b } => { /* Do something */ }
    }
    

Beyond that, you can use various patterns that allow ignoring a value, such as _ or ... In this case, you need curly braces and the .. catch-all:

OperationMode::CBC { .. } => { /* Do something */ }

See also:

Upvotes: 81

Related Questions