Start learning free

LESSON 29 OF 414 · FUNCTIONS I

Functions in Rust: Defining and Calling with fn

Lesson Read the full explanation

A function is a container for a few lines of code that perform a specific task.

Functions allow us to organize our code a lot better by breaking the code into smaller, more manageable chunks that are doing specific things.

Here's how a function definition looks like in Rust:

fn function_name() -> return_type {
	// function body (where all the instructions are written)
}

There are two main components of a function:

1. The function header:

It consists of:

  • return_type which is the type of the value returned by the function
  • function_name is the function's name, a unique identifier we use to refer to the function
  • Parentheses (()). We'll learn more about their use in next lessons
  • The -> return_type part is left out when the function returns nothing, as in the example below


2. The function body:

This is the code that Rust executes whenever the function is called.

It consists of one or more Rust statements placed inside curly brackets {} (where we have our Rust comment).

Here's an example of a function:

fn say_hello() {
	println!("Hello World");
}

The return type of this function is () (the unit type), which means the function is not returning any value. We'll learn more about this in future lessons.

Notice that we indented (added one tab before) our println!("Hello World");.

Indentation is not mandatory like in Python, but we use it to make our code easier to read.


Calling a function

If you copy paste the code we've written above in an editor and run it, you'll notice that nothing is being printed to the console.

That's because a function declaration alone does not ask the code inside the function body to run, it just declares the existence of the function.

The code inside a function body runs, or executes, only when the function is called.

You can call or invoke a function by typing its name followed by parentheses, like this:

// Function declaration:
fn say_hello() {
	println!("Hello World");
}

// Function call:
say_hello(); // Output: Hello World

All of the code inside the function body will be executed every time the function is called.

In our example, each time the function is called it will print out the message Hello World on the dev console.

We can call a function as many times as it is needed.


Assignment
Follow the Coding Tutorial and let's write some functions.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 3
    Ctrl + Enter to check

    RUST · FUNCTIONS I

    Functions in Rust, explained

    What a function is

    A function is a named block of code that performs one specific task. Instead of writing a long program as one list of instructions, you split it into small functions, each doing one thing, and give each a name. That keeps code readable, and it lets you run the same instructions many times without writing them again.

    A function definition in Rust starts with the keyword fn:

    fn say_hello() {
        println!("Hello World");
    }
    

    It has two parts.

    The header

    • The keyword fn, which starts every function definition.
    • The function's name. Rust style is snake_case: lowercase words joined by underscores, like say_hello. A name in camelCase still works, but the compiler warns about it.
    • Parentheses. They hold the function's parameters, which later lessons cover. For now they are empty.
    • Optionally, a return type written after ->, such as fn add(a: i32, b: i32) -> i32. When you write no return type, the function returns the unit value (), which means "nothing useful". say_hello has no return type, so it returns nothing.

    The body

    The body is the code that runs when the function is called. It is wrapped in curly braces { }. Here it holds one statement, println!("Hello World");. The ! after println marks it as a macro rather than an ordinary function, but you use it the same way: the text goes inside the parentheses, and the statement ends with a semicolon.

    The indentation inside the braces is for readers. Rust does not depend on it, so braces are what tell the compiler where the body begins and ends.

    Defining is not running

    A definition only tells Rust that the function exists. If you put only the definition above in a program, nothing is printed. The body runs when the function is called, and you call a function by writing its name followed by parentheses and a semicolon:

    fn say_hello() {
        println!("Hello World");
    }
    
    say_hello(); // prints: Hello World
    

    Each call runs the whole body once. Calling say_hello(); three times prints the message three times. You can call a function as often as you need.

    In a complete standalone Rust program, code that runs belongs inside a function, and execution starts in a function called main. A complete version of the example looks like this:

    fn say_hello() {
        println!("Hello World");
    }
    
    fn main() {
        say_hello();
        say_hello();
    }
    

    This program prints Hello World twice. In the lesson's editor you write the definition and the call directly, as in the earlier example.

    Order of definition

    Functions defined at the top level of a Rust file can be called from code that comes before them in the file. Rust still reads best when a function is defined above the place where it is called, and the lesson follows that order.

    The exercise, step by step

    1. Define the function. At the top of the file, write fn say_hello() with empty parentheses, because it takes no parameters, followed by a pair of braces for the body. The name is exactly say_hello, in snake_case.
    2. Fill in the body. Inside the braces, use println! to print Hello everybody!. The text goes in double quotes, and the statement ends with a semicolon.
    3. Call it. Below the definition, write say_hello();. Without this line the program prints nothing, because the definition alone never runs.
    fn say_hello() {
        println!("Hello everybody!");
    }
    
    say_hello();
    

    The output is the single line Hello everybody!.

    Common mistakes

    • Defining without calling. The function is correct, but nothing is printed.
    • Forgetting the parentheses on the call. The call is say_hello(), not say_hello. The name by itself is not a call.
    • Forgetting the braces. A header with no braces after it is a compile error: the compiler expects ->, where or { and finds the next token instead.
    • Leaving out the semicolon after println!(...). This is allowed for the last statement in a body, but a semicolon is the habit to keep.
    • Calling an undefined or misspelled name. Calling say_helo(); gives the error "cannot find function say_helo in this scope".
    • Declaring a return type you don't produce. Writing fn say_hello() -> i32 with a body that only prints is a "mismatched types" error, because the body evaluates to (), not an i32.

    Key takeaways

    • A function groups statements under a name. It is defined with fn name() { ... }.
    • Function names use snake_case. Without a -> type, a function returns nothing.
    • The body runs only when the function is called with name();, and it runs fully on every call.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free