Duncan
Duncan

Reputation: 375

Do Rust match statements require commas?

Why does this code work? Are commas in match statements just a convention?

for (index, character) in argv[1].chars().enumerate() {
match character {
    'a' | 'A' => {println!("{}: 'A'", index)}
    'e' | 'E' => {println!("{}: 'E'", index)}
    'i' | 'I' => {println!("{}: 'I'", index)}
    'o' | 'O' => {println!("{}: 'O'", index)}
    'u' | 'U' => {println!("{}: 'U'", index)}
     _        => {
                     let consonant: Vec<_> = character.to_uppercase().collect();
                     println!("{}: {:?} is not a vowel", index, consonant[0])
                 }
}

Upvotes: 21

Views: 3412

Answers (2)

Lukas Kalbertodt
Lukas Kalbertodt

Reputation: 88916

Let's take a look what the Rust reference says about this:

MatchArms :
   ( MatchArm => ( BlockExpression ,? | Expression , ) )*
   MatchArm => ( BlockExpression | Expression ) ,?

What we can see here is that on the right side of => there is always an expression, but we distinguish between two types of expressions: BlockExpression and Expression. After a BlockExpression a comma is optional (denoted by the ?), but after an normal expression the comma is required, except for the last match arm: there, the comma is always optional.

What is a BlockExpression? The reference defines it as basically two braces { } with a list of statements and an optional tail expression.

So: commas at the end of match arms are optional if:

  • it is the last match arm, or
  • if the right hand side of the arm is a block expression (stuff between two braces {}).

Unfortunately, the compiler doesn't quite agree with the reference. This works, for example:

match true {
    false => if true {
        "hi"
    } else {
        "no"
    }
    true => ""
};

Note that the right hand side of the first match arm is not a block expression, but an if-else-expression. So for the compiler the rule seems to be: if the right hand side ends with a closing brace }, the comma is optional.


As for what is idiomatic:

  • If the right hand side ends with a closing brace }, omit the comma.
  • If not: use a comma, even when it's the last match arm.

Upvotes: 29

Shepmaster
Shepmaster

Reputation: 431689

Do Rust match statements require commas?

No. Your own code proves that.

Why does this code work?

Because the designers of the language decided it should.

A match arm can have either an expression followed by a comma or a block without a comma.

Are commas in match statements just a convention?

No. When using braces, rustfmt removes the commas. Otherwise they are required.

How rustfmt puts your code:

for (index, character) in argv[1].chars().enumerate() {
    match character {
        'a' | 'A' => println!("{}: 'A'", index),
        'e' | 'E' => println!("{}: 'E'", index),
        'i' | 'I' => println!("{}: 'I'", index),
        'o' | 'O' => println!("{}: 'O'", index),
        'u' | 'U' => println!("{}: 'U'", index),
        _ => {
            let consonant: Vec<_> = character.to_uppercase().collect();
            println!("{}: {:?} is not a vowel", index, consonant[0])
        }
    }
}

Upvotes: 7

Related Questions