Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do Rust match statements require commas?

Tags:

syntax

rust

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])
                 }
}
like image 696
Duncan Avatar asked Aug 02 '18 22:08

Duncan


People also ask

How match works in Rust?

Rust has an extremely powerful control-flow operator called match that allows us to compare a value against a series of patterns and then execute code based on which pattern matches.

What is a match statement Rust?

Rust provides pattern matching via the match keyword, which can be used like a C switch . The first matching arm is evaluated and all possible values must be covered.

Does Rust have pattern matching?

Patterns are a special syntax in Rust for matching against the structure of types, both complex and simple. Using patterns in conjunction with match expressions and other constructs gives you more control over a program's control flow.

How do you match types in Rust?

Instead of matching on an element, call the method in the trait on it. TLDR: in Rust, to match over type, we create a trait, implement a function for each type and call it on the element to match. Surround it with backticks to mark it as code. Single backticks for inline code, triple backticks for code blocks.


2 Answers

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.
like image 121
Lukas Kalbertodt Avatar answered Oct 18 '22 17:10

Lukas Kalbertodt


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])
        }
    }
}
like image 42
Shepmaster Avatar answered Oct 18 '22 18:10

Shepmaster