Web Analytics

Functions

Beginner ~20 min read

Functions are the building blocks of Rust programs. You've already seen the most important function: main, the entry point of many programs. In this lesson, you'll learn how to define your own functions, pass parameters, return values, and understand the crucial difference between statements and expressions.

Defining Functions

Functions are defined using the fn keyword, followed by a name and parentheses. Rust uses snake_case for function names:

fn function_name() {
    // Function body
}
Output
Click Run to execute your code
Function Naming:
  • Use snake_case for function names
  • Names should be descriptive and verb-based
  • Examples: calculate_sum, print_message, is_valid

Function Parameters

Functions can take parameters (also called arguments). You must declare the type of each parameter:

fn print_number(x: i32) {
    println!("The number is: {}", x);
}

fn print_sum(x: i32, y: i32) {
    println!("{} + {} = {}", x, y, x + y);
}
Type Annotations Required: Unlike variable declarations, you must always specify parameter types. This is a deliberate design choice to make function signatures clear and explicit.

Return Values

Functions can return values. Declare the return type after an arrow ->:

fn add(x: i32, y: i32) -> i32 {
    x + y  // No semicolon - this is the return value
}
Output
Click Run to execute your code
Implicit Returns: In Rust, the last expression in a function is automatically returned. You can use the return keyword for early returns, but it's idiomatic to omit it for the final value.
Rust Function Flow: Parameters to Return Value

Statements vs Expressions

This is a crucial concept in Rust:

Aspect Statements Expressions
Definition Instructions that perform an action Evaluate to a value
Return value Do not return a value Return a value
Semicolon End with ; No ; at the end
Examples let x = 5; 5 + 6, { x + 1 }
Output
Click Run to execute your code
Key Point: Adding a semicolon to an expression turns it into a statement. This is why x + y returns a value, but x + y; does not.
Rust Statements vs Expressions

Common Mistakes

1. Adding semicolon to return expression

Wrong:

fn add(x: i32, y: i32) -> i32 {
    x + y;  // Error: expected i32, found ()
}

Correct:

fn add(x: i32, y: i32) -> i32 {
    x + y  // No semicolon - this is an expression
}

2. Missing parameter types

Wrong:

fn greet(name) {  // Error: expected type
    println!("Hello, {}!", name);
}

Correct:

fn greet(name: &str) {  // Type annotation required
    println!("Hello, {}!", name);
}

3. Forgetting return type annotation

Wrong:

fn multiply(x: i32, y: i32) {  // Missing -> i32
    x * y
}

Correct:

fn multiply(x: i32, y: i32) -> i32 {
    x * y
}

Exercise: Create Your Own Functions

Task: Implement the missing functions.

Requirements:

  • Implement multiply to multiply two numbers
  • Implement is_even to check if a number is even
  • Implement max to return the larger of two numbers
Output
Click Run to execute your code
Show Solution
fn main() {
    println!("5 * 3 = {}", multiply(5, 3));
    println!("Is 7 even? {}", is_even(7));
    println!("Max of 10 and 20: {}", max(10, 20));
}

fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

fn is_even(n: i32) -> bool {
    n % 2 == 0
}

fn max(a: i32, b: i32) -> i32 {
    if a > b {
        a
    } else {
        b
    }
}

Summary

  • Functions are defined with fn keyword
  • Use snake_case for function names
  • Parameter types must be declared explicitly
  • Return type is specified with -> Type
  • Statements perform actions but don't return values
  • Expressions evaluate to values
  • Last expression in a function is implicitly returned (no semicolon)
  • Use return keyword for early returns

What's Next?

You've learned the fundamentals of Rust: variables, types, and functions. In the next lesson, we'll cover comments and documentation, learning how to write clear, maintainable code and generate beautiful documentation for your Rust projects.