Module 1 • Lesson 6

Functions and Comments

📚 8 min read 💻 Free Course 🦀 nixus.pro

Functions in Rust

Functions are the building blocks of Rust programs. Rust uses fn to define functions, uses snake_case naming by convention, and has a powerful return-value system that treats functions as expressions.

// Basic function
fn greet(name: &str) {
    println!("Hello, {}!", name);
}

// Function with return value
fn add(a: i32, b: i32) -> i32 {
    a + b  // No semicolon = implicit return
}

// Explicit return
fn max(a: i32, b: i32) -> i32 {
    if a > b {
        return a;  // Early return
    }
    b  // Implicit return
}

fn main() {
    greet("Rustacean");
    println!("2 + 3 = {}", add(2, 3));
    println!("max(5,3) = {}", max(5, 3));
}

The key distinction: an expression without a semicolon returns its value. Adding a semicolon turns it into a statement that returns () (the unit type).

fn five() -> i32 {
    5   // Expression - returns 5
}

fn nothing() {
    5;  // Statement - returns () due to semicolon
}

// This would be a compile error:
// fn five_wrong() -> i32 {
//     5;  // ERROR: expected i32, found ()
// }

Functions as Expressions

In Rust, almost everything is an expression - including if, loop, and blocks. This enables clean, expressive code:

fn main() {
    // if as expression
    let x = 5;
    let description = if x > 0 { "positive" } else { "non-positive" };
    println!("{x} is {description}");

    // Block as expression
    let y = {
        let a = 3;
        let b = 4;
        a * a + b * b  // Returns 25 (no semicolon!)
    };
    println!("y = {y}");  // 25

    // loop as expression with break value
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;  // Return value from loop
        }
    };
    println!("result = {result}");  // 20
}

Comments: Three Types

/// Documentation comment - for public APIs
/// Supports Markdown formatting
/// 
/// # Examples
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
fn add(a: i32, b: i32) -> i32 {
    a + b
}

//! Module-level documentation comment
//! Describes the entire module/crate

fn main() {
    // Regular comment - ignored by compiler
    
    /* Block comment
       spans multiple lines */
    
    let x = 5; // inline comment

    // Nested block comments work in Rust!
    /* outer /* inner */ still outer */
}

Documentation comments (///) are special - they generate HTML documentation via cargo doc. Writing good doc comments is a key part of professional Rust development.

Multiple Return Values via Tuples

/// Returns (min, max) of a slice
fn min_max(numbers: &[i32]) -> (i32, i32) {
    let mut min = numbers[0];
    let mut max = numbers[0];

    for &n in numbers.iter() {
        if n < min { min = n; }
        if n > max { max = n; }
    }

    (min, max)  // Return tuple
}

/// Returns (quotient, remainder)
fn div_rem(dividend: i32, divisor: i32) -> (i32, i32) {
    (dividend / divisor, dividend % divisor)
}

fn main() {
    let nums = [3, 7, 1, 9, 2, 8, 4, 6, 5];
    let (min, max) = min_max(&nums);
    println!("Min: {min}, Max: {max}");

    let (q, r) = div_rem(17, 5);
    println!("17 / 5 = {q} remainder {r}");
}

Recursion

fn factorial(n: u64) -> u64 {
    if n <= 1 {
        1
    } else {
        n * factorial(n - 1)
    }
}

fn fibonacci(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

fn main() {
    for i in 0..=10 {
        println!("{}! = {}", i, factorial(i));
    }

    // Note: naive recursive fibonacci is slow for large n
    // We will cover better approaches later
    for i in 0..=10 {
        print!("{} ", fibonacci(i));
    }
    println!();
}
Stack Overflow

Rust does not have tail call optimization by default. Deep recursion can overflow the stack. For production code, prefer iterative solutions or use trampolining. The compiler will not warn you about non-tail recursive functions.

🎯 Practice Exercise

  1. Write a function is_prime(n: u64) -> bool that returns true if n is prime
  2. Write a function nth_prime(n: u32) -> u64 that returns the nth prime number
  3. Add documentation comments to both functions with examples
  4. Write a function that takes a &str and returns (word_count, char_count) as a tuple
  5. Run cargo doc --open to see your documentation rendered in a browser

🎉 Key Takeaways