Functions
Prerequisites: Loops
Syntax
fn name(param1: Type1, param2: Type2) -> ReturnType {
// body
final_expression
}
- Functions are declared with
fn. Names usesnake_case. - Every parameter must have a type annotation — Rust never infers parameter types.
- The return type comes after
->. Leave it out if the function returns nothing (technically it returns(), the empty "unit" value). - A function can be defined before or after the code that calls it.
Statements vs expressions
This distinction matters more in Rust than in most languages:
- A statement performs an action and produces no value, like
let x = 5;. - An expression evaluates to a value, like
5,a + b, a function call, anif, or a{ }block.
Adding a semicolon turns an expression into a statement. That's why
the last expression in a function body — written without a
semicolon — is the return value. This tail expression is the
normal way to return in Rust. The return keyword is used for
returning early.
Example
fn main() {
greet("Ada");
let total = add(2, 3);
println!("2 + 3 = {total}");
println!("area = {}", rectangle_area(4.0, 2.5));
println!("absolute(-7) = {}", absolute(-7));
println!("is 10 even? {}", is_even(10));
let y = {
let x = 3;
x * 2 // a block is an expression too
};
println!("y = {y}");
}
fn greet(name: &str) {
println!("Hello, {name}!");
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn rectangle_area(width: f64, height: f64) -> f64 {
width * height
}
fn absolute(n: i32) -> i32 {
if n < 0 {
return -n; // early return
}
n
}
fn is_even(n: i32) -> bool {
n % 2 == 0
}
&str is the type of a piece of text such as "Ada" — you'll learn
exactly what the & means in the next few lessons.
Expected output
Hello, Ada!
2 + 3 = 5
area = 10
absolute(-7) = 7
is 10 even? true
y = 6
Common mistakes
- Adding a semicolon to the tail expression:
fn add(a: i32, b: i32) -> i32 {
a + b;
}
error[E0308]: mismatched types
The compiler explains that the function "implicitly returns () as
its body has no tail or return expression" and suggests
"remove this semicolon to return this value".
- Leaving out parameter types.
fn add(a, b) -> i32fails with:
error: expected one of `:`, `@`, or `|`, found `,`
- Forgetting the
-> Typewhen the function should return a value. Without it, the function returns()and the compiler complains that it found a value where it expected().
Practice
Write a function celsius_to_fahrenheit that takes an f64 and
returns an f64 using the formula c * 9.0 / 5.0 + 32.0. Call it for
100.0 and 37.0, printing each result with one decimal place:
100.0°C = 212.0°F
37.0°C = 98.6°F
Show solution
fn celsius_to_fahrenheit(c: f64) -> f64 {
c * 9.0 / 5.0 + 32.0
}
fn main() {
for c in [100.0, 37.0] {
let f = celsius_to_fahrenheit(c);
println!("{c:.1}°C = {f:.1}°F");
}
}