Reputation: 375
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
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:
{}
).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:
}
, omit the comma.Upvotes: 29
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