↓ Skip to main content
  1. Rust/

Conditionals and Control Flow in Rust

964 words·5 mins· loading · loading · · ·Rust-basic

Introduction: Code Blocks and Expressions
#

In Rust, a code block is a fundamental syntactic unit. It does not merely group statements together; it is an expression that yields a value.

  • Syntax: Enclosed by curly braces { ... }. Inside, statements typically terminate with a semicolon ;.
  • Return Value:
    • If the final statement of the block is an expression without a trailing semicolon, its evaluated value becomes the return value of the entire block.
    • If the final statement ends with a semicolon ; (or if the block is empty), the block evaluates to the unit type () (an empty tuple).

Let’s explore code blocks, if-else expressions, and pattern matching in the interactive slides below:

Branching and Code Blocks
Step 1/3
 1fn main() {
 2    // A code block evaluates to the value of its final expression
 3    let y = {
 4        let x = 1;
 5        let z = 2;
 6        x + z // No semicolon -> returns 3
 7    };
 8
 9    // A code block ending with a semicolon returns the unit type ()
10    let u = {
11        let x = 10;
12        println!("x = {}", x);
13    };
14
15    println!("y = {}, u = {:?}", y, u);
16}

Code Blocks

  • A code block is enclosed in curly braces {}.
  • If the final expression of a block does not end with ;, its value is returned from the block.
  • A block ending with ; or an empty block returns the unit type ().

Conditionals and Branching
#

Basic if and else
#

The if construct checks a boolean predicate and executes the corresponding branch.

  • Syntax Rules:
    • The condition must not be wrapped in parentheses ( ). Adding parentheses around the condition (e.g., if (a > 5)) is considered non-idiomatic and triggers compiler linter warnings.
    • The condition expression must strictly evaluate to the bool type. Using integers (like in C or C++) triggers a compilation error.
// COMPILE ERROR: count is not a boolean
if count { ... } 

// CORRECT: expressions evaluate to bool
if count > 0 { ... }
if count != 0 { ... }

Comparison and Logical Operators
#

Used to construct conditions:

  • > (greater than), >= (greater than or equal to)
  • < (less than), <= (less than or equal to)
  • == (equality), != (inequality)
  • && (logical AND), || (logical OR)

Assigning from if Expressions
#

In Rust, if-else is an expression, which means it returns a value that can be directly bound to a variable.

  • Critical Type Rule: All branches in an if-else expression must evaluate to the exact same type.
  • Rust does not have a traditional ternary operator (? :). Instead, if-else serves this role cleanly.
// Correct: both branches produce i32
let y = if x > 100 { 2024 } else { 2025 }; 

// COMPILE ERROR: mismatched branch types (i32 vs &str):
let y = if x > 100 { 2024 } else { "2025" }; 

If the else branch is omitted, the if expression must return the unit type (), since evaluating to false produces () by default:

let u = if x > 100 { foo() }; // Valid only if foo() returns ()

Pattern Matching with if let
#

Basic if let
#

if let provides a concise alternative to match when you only care about handling a single specific pattern.

// For Option
if let Some(x) = foo_opt() {
    bar(x); // x is scoped exclusively to this block
} else {
    // Executed if the result is None
}

Chained if let (let-chains)
#

Starting with modern Rust versions, chaining multiple let pattern bindings and boolean conditions using the && operator is supported within a single if statement.

// Pattern matching combined with an additional predicate on x
if let Some(x) = foo() && x > 100 {
    todo!()
}

// Multiple pattern matches in a single condition
if let Some(x) = foo() && let Some(y) = bar() && x > y {
    todo!()
}

Test Your Knowledge
#

Take a quick interactive quiz to solidify your understanding of code blocks and branching in Rust:

Article read
Please rate how helpful and clear this article was to you
▶ Article series
About Rust - This article is part of a series.

Related