Control Flow
Control flow constructs determine the order in which code executes. Fe provides conditionals, pattern matching, and loops, all designed as expressions that can return values.
Conditionals
Section titled “Conditionals”If Expressions
Section titled “If Expressions”Use if to execute code based on a condition:
if balance > 0 { process_withdrawal()}Else Branches
Section titled “Else Branches”Add an else branch for when the condition is false:
if balance >= amount { withdraw(amount)} else { reject_transaction()}Else If Chaining
Section titled “Else If Chaining”Chain multiple conditions with else if:
let grade = if score >= 90 { "A"} else if score >= 80 { "B"} else if score >= 70 { "C"} else { "F"}If as an Expression
Section titled “If as an Expression”In Fe, if is an expression that returns a value. Both branches must return the same type:
let max = if a > b { a } else { b }
let status = if is_active { "active"} else { "inactive"}This is useful for concise conditional assignment:
let fee = if is_premium { 0 } else { calculate_fee(amount) }Pattern Matching
Section titled “Pattern Matching”Match Expressions
Section titled “Match Expressions”The match expression provides powerful pattern matching:
match value { 0 => handle_zero() 1 => handle_one() _ => handle_other()}Like if, match is an expression that returns a value:
let description = match count { 0 => "none" 1 => "one" 2 => "two" _ => "many"}Matching Enum Variants
Section titled “Matching Enum Variants”Match on enum variants to handle different cases:
enum Status { Pending, Approved, Rejected(String<64>),}
let status = Status::Pending
let message: String<64> = match status { Status::Pending => "Awaiting review" Status::Approved => "Request approved" Status::Rejected(reason) => reason // Extract the reason}Matching with Patterns
Section titled “Matching with Patterns”Use patterns to destructure and bind values:
let location = match point { (0, 0) => "origin" (0, _) => "on y-axis" (_, 0) => "on x-axis" (_, _) => "somewhere else"}Match on struct fields:
match user { User { active: true, role } => process_active(role) User { active: false, .. } => handle_inactive()}The Wildcard Pattern
Section titled “The Wildcard Pattern”Use _ to match any value you don’t need:
match result { Result::Ok(value) => use_value(value) Result::Err(_) => handle_error() // Ignore the specific error}Pattern Exhaustiveness
Section titled “Pattern Exhaustiveness”Match expressions must be exhaustive. Every possible value must be handled. The wildcard _ is often used as a catch-all:
let day_name = match day { 1 => "Monday" 2 => "Tuesday" 3 => "Wednesday" 4 => "Thursday" 5 => "Friday" 6 => "Saturday" 7 => "Sunday" _ => "Invalid day" // Handle all other values}For Loops
Section titled “For Loops”Use for to iterate over a collection:
for item in items { process(item)}Pattern Binding in For Loops
Section titled “Pattern Binding in For Loops”Destructure elements while iterating:
for (index, value) in indexed_items { store_at(index, value)}
for User { name, balance } in users { if balance > 0 { credit(name, balance) }}While Loops
Section titled “While Loops”Use while for condition-based loops:
let mut count: u256 = 5while count > 0 { process_next() count = count - 1}A common pattern for indefinite loops:
while true { if should_stop() { break } do_work()}Loop Control
Section titled “Loop Control”Use break to exit a loop early:
for item in items { if item.is_target() { found = item break // Exit the loop }}Continue
Section titled “Continue”Use continue to skip to the next iteration:
for item in items { if item.should_skip() { continue // Skip this item } process(item)}Combining Break and Continue
Section titled “Combining Break and Continue”let mut sum: u256 = 0for value in values { // Skip negative values if value < 0 { continue }
// Stop if we exceed the limit if sum + value > limit { break }
sum = sum + value}Early Return
Section titled “Early Return”Return Statement
Section titled “Return Statement”Use return to exit a function early:
fn find_user(id: u256) -> Option<User> { if id == 0 { return Option::None // Early return for invalid ID }
// ... lookup logic ...
Option::Some(user) // Implicit return}Return with Value
Section titled “Return with Value”Return a specific value from anywhere in the function:
fn calculate_discount(amount: u256, is_member: bool) -> u256 { if amount < 100 { return 0 // No discount for small amounts }
if is_member { return amount / 10 // 10% for members }
amount / 20 // 5% for non-members (implicit return)}Return vs Implicit Return
Section titled “Return vs Implicit Return”Fe functions return the value of their last expression implicitly. Use explicit return for:
- Early exits from the function
- Multiple exit points
- Clarity in complex functions
// Implicit return - last expression is the return valuefn double(x: u256) -> u256 { x * 2}
// Explicit return - needed for early exitfn safe_divide(a: u256, b: u256) -> Option<u256> { if b == 0 { return Option::None } Option::Some(a / b)}Summary
Section titled “Summary”| Construct | Syntax | Description |
|---|---|---|
if | if cond { } | Conditional execution |
if-else | if cond { } else { } | Two-way branch |
else if | if c1 { } else if c2 { } | Multi-way branch |
match | match val { pat => expr } | Pattern matching |
for | for pat in iter { } | Iteration over collection |
while | while cond { } | Condition-based loop |
break | break | Exit loop early |
continue | continue | Skip to next iteration |
return | return or return expr | Exit function early |