Hi,
I have a question about semicolons.
if true {} else {}
is an expression, not a statement.
But this code can be compiled successfully:
fn main() {
if true {} else {}
if true {} else {}
if true {} else {}
}
I think that I need semicolons after if
expressions because:
In practical terms, Rust's grammar expects statements to follow other statements. This means that you use semicolons to separate expressions from each other.
https://doc.rust-lang.org/book/functions.html#expressions-vs-statements
Why does this code work?
Thanks,
Some expressions can be statements without requiring a semicolon. Here is the relevant code from rustc.
/// Does this expression require a semicolon to be treated
/// as a statement? The negation of this: 'can this expression
/// be used as a statement without a semicolon' -- is used
/// as an early-bail-out in the parser so that, for instance,
/// if true {...} else {...}
/// |x| 5
/// isn't parsed as (if true {...} else {...} | x) | 5
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
match e.node {
ast::ExprKind::If(..) |
ast::ExprKind::IfLet(..) |
ast::ExprKind::Match(..) |
ast::ExprKind::Block(_) |
ast::ExprKind::While(..) |
ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
ast::ExprKind::ForLoop(..) => false,
_ => true,
}
}
5 Likes
Which, because of the ExprKind::Block
above, also means this is a valid function (Rust Playground)
fn main() {
{ () }
{ () }
{ () }
}
One other thing that is checked is that the result of a statement must be ()
, so this (Rust Playground):
fn main() {
{ true }
{ () }
}
fails with
2 | { true }
| ^^^^ expected (), found bool
similarly an if
and match
parsed as a statement must have all its arms resulting in ()
to be valid (commonly by putting a ;
at the end of each arm).
4 Likes
@dtolnay @Nemo157 Thanks!
I understand it.