Skip to content

Beginner · Types, control flow and functions · topic 7 of 50 · 25 min

Functions, statements and expressions

Explanation

Functions are written with fn, and every parameter needs a type. The return type comes after ->. In Rust, the last expression in a function body, written without a semicolon, is the value the function returns. Adding a semicolon by mistake turns it into a statement that returns () and causes a type error.

Why functions?

A function is a named block of code that does one job. You write it once and call it many times, with different inputs. You already know main. Rust uses snake_case names and you can define functions in any order in the file.

rust
fn main() {
    greet("Meena");
    let total = add(250, 120);
    println!("Total: {total}");
}

fn greet(name: &str) {
    println!("Namaste, {name}!");
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}
Prints: Namaste, Meena! then Total: 370. add is defined after main and that is fine.

Parameters always need types

Parameters are the inputs a function takes. In Rust you must write the type of every parameter, even when it seems obvious. This is a deliberate choice: the function's signature (its first line) then fully describes how to call it, and the compiler can check every call.

Statements and expressions

This idea is small but it explains much of Rust. A statement does something and gives back no value. let x = 5; is a statement. An expression is evaluated to a value. 5 + 6 is an expression, a call like add(1, 2) is an expression, and even a block in curly braces is an expression: its value is its last line, if that line has no semicolon.

rust
let fee = {
    let base = 1000;
    let gst = base * 18 / 100;
    base + gst          // no semicolon: this is the block's value
};
println!("{fee}");      // 1180
A block is an expression. Its last line without a semicolon becomes the value.

Returning values

The return type is written after an arrow ->. The value of the last expression in the body is returned automatically. Use the return keyword only to leave early, for example inside an if.

rust
fn discount(amount: u32) -> u32 {
    if amount < 500 {
        return 0;             // early exit
    }
    amount / 10               // the normal result
}
Orders of Rs 500 or more get 10 percent off; smaller ones get nothing.

The famous semicolon mistake

output
fn square(n: i32) -> i32 {
    n * n;
}
// error[E0308]: mismatched types
//   expected `i32`, found `()`
// help: remove this semicolon to return this value
The semicolon turns n * n into a statement, so the body returns () instead of i32.

Read that message slowly: the function promised an i32, but the body ended with a statement, so it produced the unit type (). The compiler even tells you which semicolon to remove.

Functions that return nothing

If you leave out -> and a type, the function returns (), the unit type. That is what greet above does. A function can also never return at all, written -> !, but you will rarely write that yourself.

Common mistakes

  • Forgetting parameter types: fn add(a, b) does not compile. Write fn add(a: i32, b: i32).
  • A semicolon after the last expression of a function with a return type: remove it.
  • Using return everywhere. It works, but idiomatic Rust uses the last expression and keeps return for early exits.
  • Passing the wrong number type: add(5u8, 3) when add takes i32. Convert first or change the signature.
Tip: Name functions with a verb that says what they do: calculate_emi, is_valid_pin, format_rupees. Keep each one short and focused on one job.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Functions, statements and expressions · 1/7

fn add(a: i32, b: i32) -> i32 {
    a + b
}

Functions in Rust start with fn. Every parameter has a type, and the return type comes after an arrow.

Prefer a video by a teacher? Find free videos on “rust functions statements expressions return value” on YouTube ↗

In real life: An EMI calculator for a loan app

A loan comparison website shows the monthly EMI for a car loan. The formula is put in one function with clear typed parameters, so every page that needs an EMI calls the same tested code. The function ends with the formula as its last expression.

rust
fn emi(principal: f64, yearly_rate_percent: f64, months: i32) -> f64 {
    let r = yearly_rate_percent / 12.0 / 100.0;
    let factor = (1.0 + r).powi(months);
    principal * r * factor / (factor - 1.0)
}

fn main() {
    let monthly = emi(500_000.0, 9.0, 60);
    println!("EMI: Rs {:.2}", monthly);
}
Prints the EMI for Rs 5 lakh at 9 percent for 60 months (about Rs 10,379). powi raises to a whole-number power.

Practice (0/3 done)

Task 1 · Question

What does this print? fn f(x: i32) -> i32 { let y = x + 1; y * 2 } fn main() { println!("{}", f(4)); }

Task 2 · Question

Why does this not compile? fn half(n: i32) -> i32 { n / 2; }

Task 3 · Practice

Write three functions: is_adult(age: u32) -> bool, with_gst(price: u32) -> u32 (adds 18 percent), and grade(marks: u32) -> char (A for 90+, B for 75+, C for 40+, F otherwise). Call each from main and print the results.

Quick quiz

Question 1

1.Which function signature is valid Rust?

Question 2

2.What does a function without -> return?

Question 3

3.Which of these is an expression?

Question 4

4.What is the value of this block? { let a = 2; a * 3 }

Question 5

5.When should you use the return keyword?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which function signature is valid Rust?

Answer: fn add(a: i32, b: i32) -> i32

Each parameter is name: type, and the return type follows ->.

What does a function without -> return?

Answer: The unit type ()

Without a return type, the function returns ().

Which of these is an expression?

Answer: x + 1

x + 1 produces a value. The others are statements or items.

What is the value of this block? { let a = 2; a * 3 }

Answer: 6

The last line a * 3 has no semicolon, so the block's value is 6.

When should you use the return keyword?

Answer: Only for early exits; the last expression returns automatically

Idiomatic Rust ends with an expression and uses return for leaving early.

Which is a valid single-expression function?Related

Answer: fun double(x: Int) = x * 2

Use = with an expression; parameter types are required.

From Functions

What does a function return if it has no return statement?Related

Answer: undefined

Every JavaScript function without a return value gives undefined.

From Functions: declarations, expressions and return

What does void as a return type mean?Related

Answer: The function returns nothing

void functions do their job without giving a value back.

From Functions: declare, define, call and return

What does a function return if it has no return statement?Related

Answer: undefined

Without return, a function gives back undefined.

From Functions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Types, control flow and functions” before its exam: Control flow: if, loop, while and for, Mini project: reading input from the user.
  2. Module 2 exam: Types, control flow and functions · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Ownership: Rust's big idea. 50 topics left in the course before the final exam.

← Previous: Compound types: tuples and arrays