5.3 Expressions and Statements
Rust differentiates expressions from statements more clearly than C/C++ does. Understanding this distinction is crucial for writing idiomatic Rust.
5.3.1 Expressions
An expression is code that evaluates to a value. In Rust, most constructs—such as arithmetic, comparisons, and even some control-flow structures (if, match)—are expressions.
Important: An expression on its own does not form valid standalone Rust code. You must use it in a context that consumes its result, such as assigning it to a variable, passing it to a function, or returning it from a function.
Examples:
5               // literal expression: evaluates to 5
x + y           // arithmetic expression
a > b           // comparison expression (produces a bool)
if x > y { x } else { y }  // 'if' is an expression returning either x or y5.3.2 Statements
A statement performs an action but does not directly return a value. Examples include variable declarations (let x = 5;) and expression statements (e.g., (x + y);), where the result of an expression is discarded.
Statements end with a semicolon, which “consumes” the expression’s value. Assignments are statements in Rust—unlike C, where = also returns a value.
#![allow(unused)] fn main() { let mut y = 0; let x = 5; // A statement declaring x y = x + 1; // An assignment statement }
Note: Because assignments in Rust are statements,
x = y = 5;is invalid. This design helps avoid certain side-effect bugs common in C.
Block Expressions
In Rust, a block ({ ... }) is an expression, and its value is the last expression inside it—provided that last expression does not end with a semicolon:
#![allow(unused)] fn main() { let x = { let y = 3; y + 1 // This is the last expression, so the block's result is y + 1 }; println!("x = {}", x); // 4 }
If the last expression does end with a semicolon, the block produces the unit type ():
#![allow(unused)] fn main() { let x = { let y = 3; y + 1; // The semicolon discards the value, so the block returns () }; println!("x = {:?}", x); // () }
Be careful with semicolons in blocks. An unintended semicolon can cause the block to yield () instead of the value you expected.
5.3.3 Line Structure in Rust
Rust is not line-based, so expressions and statements can span multiple lines without requiring special continuation symbols:
#![allow(unused)] fn main() { let sum = 1 + 2 + 3; }
You can also place multiple statements on a single line by separating them with semicolons:
#![allow(unused)] fn main() { let a = 5; let b = 10; println!("Sum: {}", a + b); }
Although valid, this style is generally discouraged as it can reduce readability.